你并非必须使用标准化的、基于消息的格式来向大语言模型传递上下文。
在任何给定时刻,你给 AI 智能体中的大语言模型的输入都是“这是目前为止发生的所有事情,下一步该怎么做”
一切皆是上下文工程。 大语言模型是无状态函数,它们将输入转化为输出。要获得最佳输出,你需要给它们最佳的输入。
创建优质的上下文意味着:
- 你提供给模型的提示和指令
- 你检索到的任何文档或外部数据 (例如 RAG)
- 任何过去的状态、工具调用、结果或其他历史记录
- 来自相关但独立的的任何过去消息或事件 (记忆)
- 关于输出何种结构化数据的指令
关于上下文工程
本指南旨在探讨如何从当今的模型中获得最大化的性能。值得注意的是,本指南未提及以下内容:
- 对模型参数的更改,例如 temperature, top_p, frequency_penalty, presence_penalty 等。
- 训练你自己的补全或嵌入模型
- 微调现有模型
再次强调,我不知道将上下文交给大语言模型的最佳方法是什么,但我知道你需要有能够尝试所有可能性的灵活性。
标准与自定义上下文格式
大多数大语言模型客户端使用如下所示的标准化、基于消息的格式:
[
{
"role": "system",
"content": "你是一个乐于助人的助手..."
},
{
"role": "user",
"content": "你能部署后端吗?"
},
{
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "1",
"name": "list_git_tags",
"arguments": "{}"
}
]
},
{
"role": "tool",
"name": "list_git_tags",
"content": "{\"tags\": [{\"name\": \"v1.2.3\", \"commit\": \"abc123\", \"date\": \"2024-03-15T10:00:00Z\"}, {\"name\": \"v1.2.2\", \"commit\": \"def456\", \"date\": \"2024-03-14T15:30:00Z\"}, {\"name\": \"v1.2.1\", \"commit\": \"abe033d\", \"date\": \"2024-03-13T09:15:00Z\"}]}",
"tool_call_id": "1"
}
]
虽然这种方式在大多数用例中效果很好,但如果你想真正从当今的大语言模型中获得最大化的性能,你需要以尽可能节省 Token 和注意力 (attention) 高效的方式将上下文输入到大语言模型中。
作为标准化、基于消息的格式的替代方案,你可以构建针对你的用例优化的自定义上下文格式。例如,你可以使用自定义对象,并根据需要将它们打包/散布到一个或多个用户、系统、助手或工具消息中。
这是一个将整个上下文窗口放入单个用户消息的示例:
[
{
"role": "system",
"content": "你是一个乐于助人的助手..."
},
{
"role": "user",
"content": |
这是目前为止发生的所有事情:
<slack_message>
来自: @alex
频道: #deployments
内容: 你能部署后端吗?
</slack_message>
<list_git_tags>
intent: "list_git_tags"
</list_git_tags>
<list_git_tags_result>
tags:
- name: "v1.2.3"
commit: "abc123"
date: "2024-03-15T10:00:00Z"
- name: "v1.2.2"
commit: "def456"
date: "2024-03-14T15:30:00Z"
- name: "v1.2.1"
commit: "ghi789"
date: "2024-03-13T09:15:00Z"
</list_git_tags_result>
下一步该怎么做?
}
]
模型可能会通过你提供的工具模式 (schemas) 推断出你在问 what's the next step
,但将其明确地加入到你的提示模板中总没有坏处。
代码示例
我们可以用类似下面的代码来构建它:
class Thread:
events: List[Event]
class Event:
# 可以只使用字符串,也可以是显式的 - 由你决定
type: Literal["list_git_tags", "deploy_backend", "deploy_frontend", "request_more_information", "done_for_now", "list_git_tags_result", "deploy_backend_result", "deploy_frontend_result", "request_more_information_result", "done_for_now_result", "error"]
data: ListGitTags | DeployBackend | DeployFrontend | RequestMoreInformation |
ListGitTagsResult | DeployBackendResult | DeployFrontendResult | RequestMoreInformationResult | string
def event_to_prompt(event: Event) -> str:
data = event.data if isinstance(event.data, str) \
else stringifyToYaml(event.data)
return f"<{event.type}>\n{data}\n</{event.type}>"
def thread_to_prompt(thread: Thread) -> str:
return '\n\n'.join(event_to_prompt(event) for event in thread.events)
上下文窗口示例
使用这种方法,上下文窗口可能如下所示:
初始 Slack 请求:
<slack_message>
来自: @alex
频道: #deployments
内容: 你能将最新的后端部署到生产环境吗?
</slack_message>
列出 Git 标签后:
<slack_message>
来自: @alex
频道: #deployments
内容: 你能将最新的后端部署到生产环境吗?
Thread: []
</slack_message>
<list_git_tags>
intent: "list_git_tags"
</list_git_tags>
<list_git_tags_result>
tags:
- name: "v1.2.3"
commit: "abc123"
date: "2024-03-15T10:00:00Z"
- name: "v1.2.2"
commit: "def456"
date: "2024-03-14T15:30:00Z"
- name: "v1.2.1"
commit: "ghi789"
date: "2024-03-13T09:15:00Z"
</list_git_tags_result>
错误与恢复后:
<slack_message>
来自: @alex
频道: #deployments
内容: 你能将最新的后端部署到生产环境吗?
Thread: []
</slack_message>
<deploy_backend>
intent: "deploy_backend"
tag: "v1.2.3"
environment: "production"
</deploy_backend>
<error>
运行 deploy_backend 时出错: 连接部署服务失败
</error>
<request_more_information>
intent: "request_more_information_from_human"
问题: "我连接部署服务时遇到问题,你能提供更多详细信息和/或检查一下该服务的状态吗?"
</request_more_information>
<human_response>
data:
回复: "我不确定发生了什么,你能检查一下最新工作流的状态吗?"
</human_response>
从这里开始,你的下一步可能是:
nextStep = await determine_next_step(thread_to_prompt(thread))
{
"intent": "get_workflow_status",
"workflow_name": "tag_push_prod.yaml",
}
这种类似 XML 的格式只是一个例子——重点是你可以构建适合你应用程序的自定义格式。如果你能灵活地试验不同的上下文结构,以及决定存储哪些内容与传递给大语言模型哪些内容,你将获得更好的质量。
掌控你的上下文窗口的主要好处:
- 信息密度: 以最大化大语言模型理解能力的方式来组织信息
- 错误处理: 以有助于大语言模型恢复的格式包含错误信息。一旦错误和失败的调用得到解决,可以考虑从上下文窗口中隐藏它们。
- 安全性: 控制传递给大语言模型的信息,过滤掉敏感数据
- 灵活性: 随着你对用例最佳实践的了解,不断调整格式
- Token 效率: 为 Token 效率和大语言模型的理解能力优化上下文格式
上下文包括:提示、指令、RAG 文档、历史记录、工具调用、记忆
请记住:上下文窗口是你与大语言模型交互的主要界面。掌控你组织和呈现信息的方式可以显著提升你的智能体的性能。
示例 – 信息密度 – 同样的消息,更少的 Token:
别只听我一面之词
在《12-Factor Agents》发布大约 2 个月后,上下文工程 (context engineering) 开始成为一个相当流行的术语。
此外,@lenadroid 在 2025 年 7 月也发布了一份相当不错的 上下文工程速查表。
这里反复出现的主题是:我不知道什么是最佳方法,但我知道你需要有能够尝试所有可能性的灵活性。