海外访问:www.kdjingpai.com
Ctrl + D 收藏本站
当前位置:首页 » 课程资料

《12-Factor Agents》3. 掌控你的上下文窗口

2025-07-22 35

你并非必须使用标准化的、基于消息的格式来向大语言模型传递上下文。

在任何给定时刻,你给 AI 智能体中的大语言模型的输入都是“这是目前为止发生的所有事情,下一步该怎么做”

一切皆是上下文工程。 大语言模型是无状态函数,它们将输入转化为输出。要获得最佳输出,你需要给它们最佳的输入。

创建优质的上下文意味着:

  • 你提供给模型的提示和指令
  • 你检索到的任何文档或外部数据 (例如 RAG)
  • 任何过去的状态、工具调用、结果或其他历史记录
  • 来自相关但独立的的任何过去消息或事件 (记忆)
  • 关于输出何种结构化数据的指令

《12-Factor Agents》3. 掌控你的上下文窗口-1

关于上下文工程

本指南旨在探讨如何从当今的模型中获得最大化的性能。值得注意的是,本指南未提及以下内容:

  • 对模型参数的更改,例如 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 的格式只是一个例子——重点是你可以构建适合你应用程序的自定义格式。如果你能灵活地试验不同的上下文结构,以及决定存储哪些内容与传递给大语言模型哪些内容,你将获得更好的质量。

掌控你的上下文窗口的主要好处:

  1. 信息密度: 以最大化大语言模型理解能力的方式来组织信息
  2. 错误处理: 以有助于大语言模型恢复的格式包含错误信息。一旦错误和失败的调用得到解决,可以考虑从上下文窗口中隐藏它们。
  3. 安全性: 控制传递给大语言模型的信息,过滤掉敏感数据
  4. 灵活性: 随着你对用例最佳实践的了解,不断调整格式
  5. Token 效率: 为 Token 效率和大语言模型的理解能力优化上下文格式

上下文包括:提示、指令、RAG 文档、历史记录、工具调用、记忆

请记住:上下文窗口是你与大语言模型交互的主要界面。掌控你组织和呈现信息的方式可以显著提升你的智能体的性能。

示例 – 信息密度 – 同样的消息,更少的 Token:

《12-Factor Agents》3. 掌控你的上下文窗口-2

别只听我一面之词

在《12-Factor Agents》发布大约 2 个月后,上下文工程 (context engineering) 开始成为一个相当流行的术语。

《12-Factor Agents》3. 掌控你的上下文窗口-3   《12-Factor Agents》3. 掌控你的上下文窗口-4

此外,@lenadroid 在 2025 年 7 月也发布了一份相当不错的 上下文工程速查表

《12-Factor Agents》3. 掌控你的上下文窗口-5

这里反复出现的主题是:我不知道什么是最佳方法,但我知道你需要有能够尝试所有可能性的灵活性。

相关推荐

找不到AI工具?在这试试!

输入关键词,即可 无障碍访问 必应 搜索,快速找到本站所有 AI 工具。

邮箱

联系我们

回顶部

zh_CN简体中文