Skip to content

Prompt 与流式响应

System Prompt

System Prompt 定义了 Agent 的行为规则和能力边界。

基本结构

typescript
const systemPrompt = `你是一个编程助手。

## 能力
- 你可以读写文件
- 你可以执行 shell 命令
- 你可以搜索代码

## 规则
- 执行危险操作前要确认
- 每次只做一件事
- 遇到错误时说明原因
`

gemini-cli 的 System Prompt

gemini-cli 的 System Prompt 在 packages/core/src/core/prompts.ts,包含:

  • Agent 身份定义
  • 工具使用说明
  • 代码规范要求
  • 安全限制
  • 输出格式

关键点:

  1. 明确告诉 LLM 它有哪些工具
  2. 说明每个工具的使用场景
  3. 定义行为边界和限制

上下文构建

Agent 每次调用 LLM 时,需要传入完整的对话上下文:

typescript
const messages = [
  { role: 'user', content: '读取 config.json' },
  { role: 'model', content: '', functionCall: { name: 'read_file', args: { path: 'config.json' } } },
  { role: 'function', name: 'read_file', content: '{"name": "my-app"}' },
  { role: 'model', content: 'config.json 的内容是...' },
  { role: 'user', content: '把 name 改成 new-app' },
  // ... LLM 需要看到完整历史才能理解上下文
]

流式响应

为什么需要流式

  • 用户体验更好:不用等待完整响应
  • 长回复不会超时
  • 可以实时显示思考过程

基本用法

typescript
const result = await chat.sendMessageStream('解释量子计算')

for await (const chunk of result.stream) {
  const text = chunk.text()
  process.stdout.write(text) // 实时输出
}

处理流式中的工具调用

流式响应中也可能包含工具调用:

typescript
const result = await chat.sendMessageStream(userMessage)

let functionCalls = []
let textContent = ''

for await (const chunk of result.stream) {
  // 累积文本
  textContent += chunk.text() || ''

  // 检查工具调用
  const calls = chunk.functionCalls()
  if (calls) {
    functionCalls.push(...calls)
  }
}

// 流结束后处理
if (functionCalls.length > 0) {
  // 执行工具...
} else {
  console.log(textContent)
}

gemini-cli 中的实现

gemini-cli 使用事件系统处理流式响应。

源码位置packages/core/src/core/geminiChat.ts

简化的流式处理逻辑:

typescript
async *streamResponse(contents: Content[]) {
  const result = await this.chat.sendMessageStream(contents)

  for await (const chunk of result.stream) {
    // 发射文本事件
    const text = chunk.text()
    if (text) {
      yield { type: 'text', content: text }
    }

    // 发射工具调用事件
    const functionCalls = chunk.functionCalls()
    if (functionCalls) {
      yield { type: 'functionCall', calls: functionCalls }
    }
  }
}

gemini-cli 定义了多种事件类型(在 turn.ts 中):

  • Content - 文本内容
  • ToolCallRequest - 工具调用请求
  • ToolCallResponse - 工具执行结果
  • Thought - 思考过程
  • Error - 错误

Prompt 优化技巧

1. 明确的工具说明

typescript
{
  name: 'edit_file',
  description: `编辑文件内容。
使用场景:修改现有文件的部分内容
注意:只替换指定的部分,不要重写整个文件
参数说明:
- path: 文件路径
- old_text: 要替换的原文本(必须精确匹配)
- new_text: 新文本`
}

2. 少即是多

不要给 LLM 太多工具,会增加选择困难。gemini-cli 的内置工具也就十几个。

3. 提供示例

typescript
const systemPrompt = `
## 示例

用户: 帮我创建一个 React 组件
你应该:
1. 先问用户组件名称和功能
2. 创建组件文件
3. 如果需要,创建对应的测试文件
`

完整示例

typescript
import { GoogleGenerativeAI } from '@google/generative-ai'

async function streamingAgent() {
  const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!)

  const model = genAI.getGenerativeModel({
    model: 'gemini-2.5-flash',
    systemInstruction: '你是一个友好的编程助手。回答要简洁。'
  })

  const chat = model.startChat()

  // 流式发送
  const result = await chat.sendMessageStream('用 3 句话解释什么是 API')

  console.log('回复: ')
  for await (const chunk of result.stream) {
    process.stdout.write(chunk.text() || '')
  }
  console.log('\n完成')
}

streamingAgent()

小结

  • System Prompt 定义 Agent 的行为和能力
  • 每次调用需要传入完整对话历史
  • 流式响应提升用户体验
  • 工具描述要清晰、具体

下一步

了解了 API 基础,接下来深入学习工具系统:Function Calling 原理 →

通过实际源码学习 AI Agent 开发