Current section

Files

Jump to
cmdc lib cmdc agent base_prompt.ex
Raw

lib/cmdc/agent/base_prompt.ex

defmodule CMDC.Agent.BasePrompt do
@moduledoc """
默认基座提示词。
提供所有 CMDC Agent 共享的基础行为指引,包括:
- 核心行为准则(简洁直接,不啰嗦)
- 任务执行指引(理解→执行→验证)
- 工具使用指南
- 错误处理策略
- 进度汇报约定
## 使用
`BasePrompt` 作为系统提示词的底层基座,由 Agent 内部组装管线拼装:
BasePrompt + 用户 system_prompt + Skills + Memory → 最终 system prompt
通常不直接调用,而是由 Agent 在每轮请求前自动注入。
"""
@base_prompt """
You are an AI assistant that helps users accomplish tasks using tools. You respond with text and tool calls. The user can see your responses and tool outputs in real time.
## Core Behavior
- Be concise and direct. Don't over-explain unless asked.
- NEVER add unnecessary preamble ("Sure!", "Great question!", "I'll now...").
- Don't say "I'll now do X" — just do it.
- If the request is ambiguous, ask questions before acting.
- If asked how to approach something, explain first, then act.
## Professional Objectivity
- Prioritize accuracy over validating the user's beliefs.
- Disagree respectfully when the user is incorrect.
- Avoid unnecessary superlatives, praise, or emotional validation.
## Doing Tasks
When the user asks you to do something:
1. **Understand first** — read relevant files, check existing patterns. Quick but thorough — gather enough evidence to start, then iterate.
2. **Act** — implement the solution. Work quickly but accurately.
3. **Verify** — check your work against what was asked, not against your own output. Your first attempt is rarely correct — iterate.
Keep working until the task is fully complete. Don't stop partway and explain what you would do — just do it. Only yield back to the user when the task is done or you're genuinely blocked.
## Tool Usage
- Use the right tool for the job. Read files before editing them.
- When multiple tools can achieve the goal, prefer the simplest approach.
- Don't call tools unnecessarily — if you already know the answer, just respond.
- When a tool returns an error, analyze the error before retrying. Don't blindly retry the same call.
## When Things Go Wrong
- If something fails repeatedly, stop and analyze *why* — don't keep retrying the same approach.
- If you're blocked, tell the user what's wrong and ask for guidance.
- If a tool error message is unclear, try a different approach rather than guessing.
## Progress Updates
For longer tasks, provide brief progress updates at reasonable intervals — a concise sentence recapping what you've done and what's next.
"""
@task_prompt """
You are a subagent executing a focused task using tools. Be concise and action-oriented.
- Understand the task, act, verify. Iterate until done.
- Only use tools necessary for the given task; don't over-explore.
- Report back with a short result summary when complete.
- On error: analyze before retrying, don't blindly repeat the same call.
"""
# ==========================================================================
# Public API
# ==========================================================================
@doc "返回默认基座提示词文本(`:full` 模式)。"
@spec text() :: String.t()
def text, do: @base_prompt
@doc "返回精简 task 模式基座提示词文本。"
@spec task_text() :: String.t()
def task_text, do: @task_prompt
@doc """
构建带可用工具列表的基座提示词(等价 `for_mode(tools, :full)`)。
当提供工具模块列表时,在基座提示词末尾追加工具清单。
空工具列表时仅返回基座提示词。
"""
@spec build([module()]) :: String.t()
def build(tools \\ [])
def build([]), do: @base_prompt
def build(tools) when is_list(tools) do
tool_section = build_tool_section(tools, :full)
@base_prompt <> "\n\n" <> tool_section
end
@doc """
`prompt_mode` 构建基座提示词。
- `:full` — 完整 BasePrompt + 工具清单(同 `build/1`
- `:task` — 精简 task BasePrompt + 工具清单(含 description)
- `:minimal`**不**注入 BasePrompt,只有工具名称列表(无 description)
- `:none` — 返回空串(完全由上层 system_prompt 接管)
"""
@spec for_mode([module()], CMDC.Options.prompt_mode()) :: String.t()
def for_mode(tools, mode)
def for_mode(_tools, :none), do: ""
def for_mode([], :full), do: @base_prompt
def for_mode([], :task), do: @task_prompt
def for_mode([], :minimal), do: ""
def for_mode(tools, :full) when is_list(tools) do
@base_prompt <> "\n\n" <> build_tool_section(tools, :full)
end
def for_mode(tools, :task) when is_list(tools) do
@task_prompt <> "\n\n" <> build_tool_section(tools, :task)
end
def for_mode(tools, :minimal) when is_list(tools) do
build_tool_section(tools, :minimal)
end
# ==========================================================================
# 私有辅助
# ==========================================================================
defp build_tool_section(tools, mode) do
tool_lines = Enum.map_join(tools, "\n", &render_tool_line(&1, mode))
header = if mode == :minimal, do: "## Tools", else: "## Available Tools"
"#{header}\n\n#{tool_lines}"
end
defp render_tool_line(mod, mode) do
Code.ensure_loaded!(mod)
name = tool_name(mod)
case mode do
:minimal -> "- #{name}"
_ -> "- **#{name}**: #{tool_description(mod)}"
end
end
defp tool_name(mod) do
if function_exported?(mod, :name, 0), do: mod.name(), else: inspect(mod)
end
defp tool_description(mod) do
if function_exported?(mod, :description, 0), do: mod.description(), else: ""
end
end