OpenCode 构建提示词

OpenCode 构建提示词

1. 构建系统提示词

1.1 调用处理器前获取的系统提示词

在src/session/prompt.ts的loop函数中会创建系统提示词:

const system = [
  ...(await SystemPrompt.environment(model)),  // 环境信息
  ...(await InstructionPrompt.system())        // 指令文件
]

返回的系统提示词当做processor.process函数的参数传入:

const result = await processor.process({
  ......
  system,
  ......
})

1.1.1 SystemPrompt.environment

位置: src/session/system.ts:29-53

export async function environment(model: Provider.Model) {
  return [
    `You are powered by the model named ${model.api.id}...`,
    `Working directory: ${Instance.directory}`,
    `Is directory a git repo: ${project.vcs === "git" ? "yes" : "no"}`,
    `Platform: ${process.platform}`,
    `Today's date: ${new Date().toDateString()}`,
    // ...
  ]
}

1.2 InstructionPrompt.system 的作用

位置: src/session/instruction.ts

InstructionPrompt 负责加载和管理额外的指令文件:

const FILES = [
  "AGENTS.md",
  "CLAUDE.md",
  "CONTEXT.md",  // deprecated
]

export async function system() {
  const paths = await systemPaths()

  const files = Array.from(paths).map(async (p) => {
    const content = await Bun.file(p).text().catch(() => "")
    return content ? "Instructions from: " + p + "\n" + content : ""
  })

  // 也支持从 URL 加载
  const fetches = urls.map((url) => fetch(url)...)

  return Promise.all([...files, ...fetches]).then((result) => result.filter(Boolean))
}

1.3 指令文件查找顺序

1.3.1 文件查找优先级

FILES 数组定义了查找顺序:["AGENTS.md", "CLAUDE.md", "CONTEXT.md"]

位置:src/session/instruction.ts:13-17

const FILES = [
  "AGENTS.md",
  "CLAUDE.md",
  "CONTEXT.md", // deprecated
]
1.3.2 项目目录查找(替换关系)

位置:src/session/instruction.ts:75-84

for (const file of FILES) {
  const matches = await Filesystem.findUp(file, Instance.directory, Instance.worktree)
  if (matches.length > 0) {
    matches.forEach((p) => { paths.add(path.resolve(p)) })
    break  // ← 关键:找到第一个存在的文件类型就停止
  }
}

查找逻辑:

  1. 在当前目录向上查找 AGENTS.md
  2. 如果没找到,在当前目录向上查找 CLAUDE.md
  3. 如果没找到,在当前目录向上查找 CONTEXT.md
  4. 找到任意一个就停止查找其他文件名

是替换关系:当前目录有 AGENTS.md 就不会查找 CLAUDE.md 和 CONTEXT.md。

1.3.3 全局目录查找

位置:src/session/instruction.ts:19-29, 87-92

function globalFiles() {
  const files = []
  if (Flag.OPENCODE_CONFIG_DIR) {
    files.push(path.join(Flag.OPENCODE_CONFIG_DIR, "AGENTS.md"))
  }
  files.push(path.join(Global.Path.config, "AGENTS.md"))
  if (!Flag.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT) {
    files.push(path.join(os.homedir(), ".claude", "CLAUDE.md"))
  }
  return files
}

for (const file of globalFiles()) {
  if (await Bun.file(file).exists()) {
    paths.add(path.resolve(file))
    break  // ← 找到第一个存在的就停止
  }
}
1.3.4 项目目录和全局目录的关系(叠加关系)
来源 结果
项目目录 找到一个文件(AGENTS.md 或 CLAUDE.md 或 CONTEXT.md)
全局目录 找到一个文件
最终 两个文件叠加(如果都存在)

不是替换:当前目录有 CLAUDE.md 不会阻止查找全局目录的文件。

1.3.5 文件都不存在时

如果所有指令文件都不存在:

  • paths 为空 Set
  • InstructionPrompt.system() 返回空内容
  • 只使用 agent 默认提示词 + 环境信息 + 用户输入

1.4 完整的 system 提示词组成

1.4.1 system 提示词的堆栈

位置:src/session/llm.ts:67-79

const system = []
system.push(
  [
    // 1. agent 提示词 或 提供商默认提示词
    ...(input.agent.prompt ? [input.agent.prompt] : SystemPrompt.provider(input.model)),
    // 2. 环境信息 + 指令文件内容(来自 prompt.ts)
    ...input.system,
    // 3. 用户消息中的自定义系统提示词
    ...(input.user.system ? [input.user.system] : []),
  ]
    .filter((x) => x)
    .join("\n"),
)

system 提示词堆栈:

┌─────────────────────────────────────────────────────────────┐
│                      system 提示词                          │
├─────────────────────────────────────────────────────────────┤
│ 1. agent.prompt 或 SystemPrompt.provider(model)            │
│    - agent 自定义提示词,或根据模型提供商返回默认提示词       │
├─────────────────────────────────────────────────────────────┤
│ 2. SystemPrompt.environment(model)                          │
│    - 模型信息、工作目录、平台、日期等                        │
├─────────────────────────────────────────────────────────────┤
│ 3. InstructionPrompt.system()                               │
│    - AGENTS.md / CLAUDE.md / CONTEXT.md 内容               │
├─────────────────────────────────────────────────────────────┤
│ 4. user.system                                              │
│    - 用户消息中附带的自定义系统提示词                        │
└─────────────────────────────────────────────────────────────┘

1.4.2 agent.prompt 的来源

从 agent 配置中获取,不同 agent 有不同的提示词:

// agent.ts 中的定义
export const AgentSchema = z.object({
  name: z.string(),
  prompt: z.string().optional(),  // ← 自定义提示词
  // ...
})

// 内置 Agent 示例
const agents = {
  build: { prompt: "You are a helpful coding assistant..." },
  plan: { prompt: "You are a planning assistant..." },
  compaction: { prompt: "Summarize the conversation..." },
  // ...
}

1.4.3 调用 API 时的消息结构

位置:src/session/llm.ts:229-237

messages: [
  ...system.map((x): ModelMessage => ({
    role: "system",   // ← 明确是 system 角色
    content: x,
  })),
  ...input.messages,  // ← 用户消息历史(user/assistant 交替)
]

系统提示词和用户输入不在同一个字段:

  • system → { role: "system", content: "..." }
  • input.messages → { role: "user/assistant", content: "..." }

1.1.2 SystemPrompt.provider

位置: src/session/system.ts:19-27

根据模型类型选择不同的提示词模板:

  • GPT/O1/O3: PROMPT_BEAST
  • Gemini: PROMPT_GEMINI
  • Claude: PROMPT_ANTHROPIC
  • 其他: PROMPT_ANTHROPIC_WITHOUT_TODO

1.4.4 总结

问题 答案
agent.prompt 是系统还是用户提示词? 系统提示词,role: "system"
系统提示词和用户输入是否同字段? 不是,分开传递给 AI SDK
存在 AGENTS.md 是否替换 agent.prompt? 不是替换,是叠加,都会被使用
agent.prompt 从哪获取? agent 配置中定义,不同 agent 有不同提示词

2. 构建用户提示词

2.1 createUserMessage 函数

位置: src/session/prompt.ts:957-1325

主要处理:

  • 解析 agent 引用
  • 解析文件引用(@file 语法)
  • 处理 MCP 资源
  • 调用 ReadTool 预读取文件

2.2 insertReminders 函数

位置: src/session/prompt.ts:1327-1465

根据当前 agent 和历史添加提醒:

  • plan agent: 添加规划模式提示
  • 从 plan 切换到 build: 添加切换提示
posted @ 2026-02-19 21:54  不歪歪  阅读(453)  评论(0)    收藏  举报