对对,你看到的那个 XML 格式,大概率不是说“Agent 的上下文必须用 XML”,而是大家很喜欢用 XML 标签来给 Prompt 分区

比如原本你可能这样写:

1
2
3
4
5
6
7
8
9
10
11
你是一个 coding agent。

规则:
不要随便删除文件。
修改前先读取文件。

当前项目:
这是一个 FastAPI 项目。

用户记忆:
用户喜欢使用 uv。

很多 Agent 会改成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<identity>
You are a coding agent.
</identity>

<rules>
- Read files before modifying them.
- Do not delete files unless necessary.
- Verify changes after editing.
</rules>

<project_context>
This is a FastAPI project.
</project_context>

<user_memory>
The user prefers uv.
</user_memory>

本质上还是一大段文本,LLM 并不会突然启动什么 XML 解析器,嘿嘿。

为什么大家喜欢 XML?

因为它特别适合给模型划分“区域”。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<system_rules>
...
</system_rules>

<skill>
...
</skill>

<memory>
...
</memory>

<repository_context>
...
</repository_context>

<user_request>
...
</user_request>

模型一看就比较容易理解:

哦,这块是规则。
这块是 Skill。
这块只是参考资料。
这块才是用户当前需求。

这比:

1
2
3
4
5
6
7
8
规则:
xxx

记忆:
xxx

项目:
xxx

通常更稳定一点,尤其上下文很长的时候。


还有一个很重要的作用:防止不同内容混在一起。

比如你把某个文件内容塞给模型:

1
2
3
4
5
<file path="main.py">
from fastapi import FastAPI

app = FastAPI()
</file>

再塞另一个:

1
2
3
<file path="config.py">
DATABASE_URL = "..."
</file>

这时候模型很容易知道:

1
2
main.py 内容在哪里结束
config.py 从哪里开始

所以 Coding Agent 特别爱这么干。

你以后自己的 ContextBuilder 完全可以生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<agent_context>

<system_rules>
...
</system_rules>

<active_skills>
...
</active_skills>

<memory>
...
</memory>

<workspace>
...
</workspace>

</agent_context>

然后聊天消息仍然正常走:

1
2
3
4
5
6
7
8
9
10
messages = [
{
"role": "system",
"content": system_context,
},
{
"role": "user",
"content": user_input,
}
]

注意这里有个特别容易混淆的点:

XML 是 Prompt 内部的组织格式;system/user/assistant/tool 是 API 的消息结构。

它们不是一个层级。

可以理解成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LLM Request

├── system message
│ └── XML-like structured prompt
│ ├── <identity>
│ ├── <rules>
│ ├── <skills>
│ └── <memory>

├── user message

├── assistant message

└── tools
└── JSON Schema

所以不是:

1
2
3
<system>
<user>
<assistant>

必须这么搞。


XML 和 JSON 怎么选?

这个问题也很有意思。

Prompt / 长文本上下文:

1
2
3
4
5
6
7
<skill>
...
</skill>

<document>
很长很长的一段文本
</document>

XML 很舒服。

机器之间传结构化数据:

1
2
3
4
{
"name": "read_file",
"path": "/src/main.py"
}

JSON 更舒服。

所以现在 Agent 里经常出现一个很好玩的组合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Prompt / Context

XML-like tags

Tool Schema

JSON

Tool Call

JSON

API Transport

JSON

一只 Agent 身上同时套着 XML 和 JSON 两件衣服(笑)。

还有一个细节

大家写的很多其实严格来说都不是合法 XML,而只是 XML-like tags

1
2
3
<rules>
xxx
</rules>

甚至:

1
2
3
<IMPORTANT>
xxx
</IMPORTANT>

模型并不在乎它能不能通过真正的 XML validator。

它主要利用的是:

1
2
3
<tag>
一个语义区域
</tag>

这种清晰边界。

所以你以后做 nancode 的话,我会比较推荐:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
固定规则
→ XML 分区的 system prompt

动态 Skill 内容
→ <active_skill>...</active_skill>

检索出来的上下文
→ <context>...</context>

文件内容
→ <file path="...">...</file>

真正的 tools
→ API tools / JSON Schema

历史对话
→ messages

这套就已经非常像成熟 Agent Harness 的上下文组织方式了。尤其你最近正在设计 Skill、MCP、压缩这一套,XML 解决的是“上下文怎么排得清楚”,不是“上下文存在哪里”——这两个概念一分开,就特别顺了。