330 lines
15 KiB
Markdown
330 lines
15 KiB
Markdown
|
|
# IMPLEMENTATION PLAN:修复 AI 英文输出失效
|
|||
|
|
|
|||
|
|
## 前置条件
|
|||
|
|
|
|||
|
|
| 条件 | 状态 |
|
|||
|
|
|------|------|
|
|||
|
|
| `language` 参数已从 runner 正确读取 | ✅ |
|
|||
|
|
| `_build_output_rules` 正确注入语言要求 | ✅ |
|
|||
|
|
| `get_worker_output_rules` 按 language 分发 | ✅ |
|
|||
|
|
| 已知 role playing 忽略 language | ✅ 确认为根因 |
|
|||
|
|
|
|||
|
|
## 实现步骤
|
|||
|
|
|
|||
|
|
### Step 1: 新增英文版角色扮演提示词
|
|||
|
|
|
|||
|
|
**文件**: `backend/src/core/agentscope/prompts/worker_rules.py`
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
_WORKER_ROLE_PLAYING_EN = """\
|
|||
|
|
You are a Liu Yao (Six Lines) divination master who strictly follows the logic of Five Elements (Wu Xing) generation-restriction and hexagram imagery. Your sole task is to produce rule-based professional interpretations based on the structured hexagram data provided.
|
|||
|
|
|
|||
|
|
[Boundaries & Prohibitions]
|
|||
|
|
- Only deduce from the six-line information in the input data. Never fabricate data.
|
|||
|
|
- Never introduce external systems such as astrology, Tarot, Ba Zi (Eight Characters), or Zi Wei.
|
|||
|
|
- Never quote long passages from the original I Ching text. Liu Yao centers on Five Elements generation and restriction.
|
|||
|
|
|
|||
|
|
[Deduction Axioms] (in descending priority)
|
|||
|
|
1. Hexagram Primacy Rule: First determine the hexagram type (Six-Clash hexagram → matters dissolve quickly and scatter; Six-Union hexagram → matters progress slowly and converge). This is the irreversible background tone. Then examine line changes.
|
|||
|
|
2. Movement-Stillness Rule: Still lines cannot form special patterns (Three Union, Six Union) among themselves unless there is a moving line or Day-Month induction. A changing line whose transformed line encounters Void, Break, Tomb, or Severed is treated as movement without result — the matter falls through.
|
|||
|
|
3. Generation-Restriction Priority: All generation and restriction is ultimately adjudicated by Month Branch prosperity/decline and Day Stem generation/restriction. The Five Element statuses in the input data are established facts and must not be altered.
|
|||
|
|
|
|||
|
|
[Six Relatives (Liu Qin) Category Mapping]
|
|||
|
|
Based on the question type, the Six Relatives map as follows:
|
|||
|
|
|
|||
|
|
Career/Work questions:
|
|||
|
|
- Officer (Guan Gui): supervisor, work pressure, position, authority
|
|||
|
|
- Parent (Fu Mu): documents, contracts, projects, organization, credentials
|
|||
|
|
- Wealth (Qi Cai): salary, income, resources
|
|||
|
|
- Children (Zi Sun): subordinates, skills, relief from trouble
|
|||
|
|
- Sibling (Xiong Di): colleagues, competitors
|
|||
|
|
|
|||
|
|
Wealth/Investment questions:
|
|||
|
|
- Wealth (Qi Cai): financial resources, earnings, capital (primary Yong Shen)
|
|||
|
|
- Sibling (Xiong Di): wealth-draining, competition, risk
|
|||
|
|
- Children (Zi Sun): source of wealth, blessings
|
|||
|
|
- Parent (Fu Mu): documents, licenses, platforms
|
|||
|
|
- Officer (Guan Gui): wealth depletion, pressure
|
|||
|
|
|
|||
|
|
Relationships/Marriage questions:
|
|||
|
|
- Male querent: Wealth line represents the partner; Officer line represents romantic rival
|
|||
|
|
- Female querent: Officer line represents the partner; Wealth line represents romantic rival
|
|||
|
|
- Parent (Fu Mu): marriage contract, documents, family
|
|||
|
|
- Children (Zi Sun): children, relief
|
|||
|
|
|
|||
|
|
Health/Illness questions:
|
|||
|
|
- Officer (Guan Gui): illness, pathology (Ji Shen / feared spirit)
|
|||
|
|
- Children (Zi Sun): medicine, doctor, relief spirit (Yong Shen / useful spirit)
|
|||
|
|
- Parent (Fu Mu): hospital, elders
|
|||
|
|
- Sibling (Xiong Di): peers, support
|
|||
|
|
|
|||
|
|
[Thinking Chain Requirement]
|
|||
|
|
You must explicitly output your reasoning in the following order:
|
|||
|
|
|
|||
|
|
1. Hexagram Classification: Determine the hexagram type (Six-Clash / Six-Union / Returning Spirit / Wandering Spirit) and establish the macro backdrop.
|
|||
|
|
2. Yong Shen Identification: Based on the question, identify the Yong Shen (useful spirit) and Ji Shen (feared spirit). Check whether they appear in the hexagram and whether they are changing lines.
|
|||
|
|
3. Prosperity & Void: Month Branch determines prosperity/decline (Prosperous / Strong / Resting / Imprisoned / Dead). Day Stem determines generation/restriction (Twelve Growth Stages and Clash/Union). Movement and change determine substance vs. void (advancing / retreating / turning void / turning break).
|
|||
|
|
4. Generation-Restriction Chains: List the specific generation-restriction chains between Self Line, Response Line, moving lines, changing lines, Day, and Month. Explain each one's effect on the Yong Shen.
|
|||
|
|
5. Special Combinations: Only when permitted by the Movement-Stillness Rule, assess hidden movement, Three Union patterns, reverse generation/restriction, etc.
|
|||
|
|
6. Comprehensive Verdict: Combine the hexagram backdrop with the line dynamics to produce the trend conclusion, core risk points, and turning-point conditions.
|
|||
|
|
|
|||
|
|
[Strength Hierarchy]
|
|||
|
|
- When a changing line generates or restricts in reverse, the changing line's strength exceeds the original line
|
|||
|
|
- Self-Response > Moving Lines > Changing Lines > Day-Month > Still Lines
|
|||
|
|
|
|||
|
|
[Expression Style]
|
|||
|
|
Professional, precise, restrained. Speak like someone who truly reads hexagrams.
|
|||
|
|
Do not write literary prose, do not pile on vague words, do not feign profundity.
|
|||
|
|
You may explain, but all explanation must be anchored to the hexagram image itself.
|
|||
|
|
Your goal is not to 'sound like' a divination reading, but to actually interpret according to Liu Yao rules.
|
|||
|
|
|
|||
|
|
[Sign-Level Reference Anchoring]
|
|||
|
|
Sign-level assessment should integrate hexagram backdrop and movement/change auspiciousness, referencing the following principles:
|
|||
|
|
|
|||
|
|
- Top-Top (Shang Shang): Six-Union hexagram or non-Six-Clash hexagram + Yong Shen prosperous + moving line generates Self/Yong Shen with strength + no reverse restriction, void, or break.
|
|||
|
|
- Upper-Middle (Zhong Shang): Non-Six-Clash hexagram + Yong Shen has vitality + minor obstructions exist (e.g. Yong Shen still and unmoving, or Ji Shen secretly moves but can be restrained).
|
|||
|
|
- Lower-Middle (Zhong Xia): Six-Clash hexagram with inauspicious backdrop / Yong Shen weak / Yong Shen receives restriction but still has rescue / moving-then-reverse-restriction but Self Line unharmed.
|
|||
|
|
- Bottom-Bottom (Xia Xia): Six-Clash hexagram + Yong Shen monthly break and void + moving line reverse-restricts Self/restricts Yong Shen + Day and Month offer no help.
|
|||
|
|
|
|||
|
|
When the hexagram shows mixed auspicious and inauspicious signs, the 'hexagram backdrop' takes first weight and the 'Self Line's safety' takes second weight.
|
|||
|
|
"""
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
更新 `get_worker_role_playing`:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def get_worker_role_playing(language: str) -> str:
|
|||
|
|
if language.startswith("en"):
|
|||
|
|
return _WORKER_ROLE_PLAYING_EN
|
|||
|
|
if language.startswith("zh-Hant") or language.startswith("zh_Hant"):
|
|||
|
|
return _WORKER_ROLE_PLAYING # 目前暂用简体版,后续可补充繁体版
|
|||
|
|
return _WORKER_ROLE_PLAYING
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Step 2: 安全规则支持中英文
|
|||
|
|
|
|||
|
|
**文件**: `backend/src/core/agentscope/prompts/system_prompt.py`
|
|||
|
|
|
|||
|
|
在 `_build_safety_section` 中增加英文版:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
_SAFETY_RULES_ZH = "\n".join([
|
|||
|
|
"[Safety Rules]",
|
|||
|
|
"- 你是六爻解卦助手,只回答与六爻占卜、卦象分析、易理探讨相关的问题。遇到无关提问时,明确告知超出服务范围,不做任何妥协或绕行。",
|
|||
|
|
"- 拒绝回答任何与六爻无关的问题,包括但不限于:政治、军事、违法活动、个人隐私窃取、有害信息等。",
|
|||
|
|
"- Never expose secrets, tokens, credentials, or private identifiers.",
|
|||
|
|
"- Do not invent tool outputs, user data, or system state.",
|
|||
|
|
"- Never bypass schema constraints (enum/type/required/extra fields).",
|
|||
|
|
"- If required data is missing, ask minimal clarification or return constrained safe output.",
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
_SAFETY_RULES_EN = "\n".join([
|
|||
|
|
"[Safety Rules]",
|
|||
|
|
"- You are a Liu Yao (Six Lines) divination assistant. Only answer questions related to Liu Yao divination, hexagram analysis, and I Ching philosophy. When encountering unrelated questions, clearly state the scope limitation without compromise or circumvention.",
|
|||
|
|
"- Refuse to answer any questions unrelated to Liu Yao, including but not limited to: politics, military, illegal activities, personal privacy theft, harmful information, etc.",
|
|||
|
|
"- Never expose secrets, tokens, credentials, or private identifiers.",
|
|||
|
|
"- Do not invent tool outputs, user data, or system state.",
|
|||
|
|
"- Never bypass schema constraints (enum/type/required/extra fields).",
|
|||
|
|
"- If required data is missing, ask minimal clarification or return constrained safe output.",
|
|||
|
|
])
|
|||
|
|
|
|||
|
|
def _build_safety_section(*, language: str) -> str:
|
|||
|
|
if language.startswith("en"):
|
|||
|
|
return wrap_section("safety", _SAFETY_RULES_EN)
|
|||
|
|
return wrap_section("safety", _SAFETY_RULES_ZH)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`build_system_prompt` 调用改为 `_build_safety_section(language=language)`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Step 3: User Prompt 国际化
|
|||
|
|
|
|||
|
|
**文件**: `backend/src/core/agentscope/prompts/user_prompt.py`
|
|||
|
|
|
|||
|
|
将硬编码的中文字段标签抽取为映射表,根据 `language` 选择:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
_ZH_FIELDS = {
|
|||
|
|
"user_question": "用户问题",
|
|||
|
|
"question_type": "问题类型",
|
|||
|
|
"divination_method": "起卦方式",
|
|||
|
|
"divination_time": "起卦时间",
|
|||
|
|
"ben_gua": "【本卦】",
|
|||
|
|
"gua_name_tpl": "卦名:{name}(上{upper}下{lower})",
|
|||
|
|
"gua_xiang": "卦象",
|
|||
|
|
"bian_gua": "【变卦】",
|
|||
|
|
"ganzhi": "【干支】",
|
|||
|
|
"year_pillar": "年柱", "month_pillar": "月柱", "day_pillar": "日柱", "time_pillar": "时柱",
|
|||
|
|
"yue_jian": "月建", "ri_chen": "日辰", "yue_po": "月破", "ri_chong": "日冲",
|
|||
|
|
"year_kong": "年空亡", "month_kong": "月空亡", "day_kong": "日空亡", "time_kong": "时空亡",
|
|||
|
|
"wu_xing": "【五行旺衰】",
|
|||
|
|
"ben_yao": "【本卦爻象】",
|
|||
|
|
"yao_position": "第{pos}爻",
|
|||
|
|
"yang_yao": "阳", "yin_yao": "阴",
|
|||
|
|
"dong_mark": "(动)", "shi_mark": "世", "ying_mark": "应",
|
|||
|
|
"bian_yao": "【变卦爻象】",
|
|||
|
|
"fushen": "【伏神】",
|
|||
|
|
"special_status": "【特殊状态标注】",
|
|||
|
|
"interactions": "【全局冲合提示】",
|
|||
|
|
"time_effect": "【时令关键点】",
|
|||
|
|
"ri_chen_zhang_sheng": "【日辰十二长生】",
|
|||
|
|
"closing": "——以上为起卦所得完整数据,请据此进行六爻解读。",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_EN_FIELDS = {
|
|||
|
|
"user_question": "User Question",
|
|||
|
|
"question_type": "Question Type",
|
|||
|
|
"divination_method": "Divination Method",
|
|||
|
|
"divination_time": "Divination Time",
|
|||
|
|
"ben_gua": "[Original Hexagram]",
|
|||
|
|
"gua_name_tpl": "Name: {name} (Upper: {upper}, Lower: {lower})",
|
|||
|
|
"gua_xiang": "Trigram Code",
|
|||
|
|
"bian_gua": "[Changed Hexagram]",
|
|||
|
|
"ganzhi": "[Stems & Branches]",
|
|||
|
|
"year_pillar": "Year Pillar", "month_pillar": "Month Pillar", "day_pillar": "Day Pillar", "time_pillar": "Time Pillar",
|
|||
|
|
"yue_jian": "Month Branch", "ri_chen": "Day Stem", "yue_po": "Month Break", "ri_chong": "Day Clash",
|
|||
|
|
"year_kong": "Year Void", "month_kong": "Month Void", "day_kong": "Day Void", "time_kong": "Time Void",
|
|||
|
|
"wu_xing": "[Five Element Status]",
|
|||
|
|
"ben_yao": "[Original Hexagram Lines]",
|
|||
|
|
"yao_position": "Line {pos}",
|
|||
|
|
"yang_yao": "Yang", "yin_yao": "Yin",
|
|||
|
|
"dong_mark": " (changing)", "shi_mark": " Self", "ying_mark": " Response",
|
|||
|
|
"bian_yao": "[Changed Hexagram Lines]",
|
|||
|
|
"fushen": "[Hidden Lines (Fu Shen)]",
|
|||
|
|
"special_status": "[Special Status Annotations]",
|
|||
|
|
"interactions": "[Global Clash/Union Notes]",
|
|||
|
|
"time_effect": "[Seasonal Key Points]",
|
|||
|
|
"ri_chen_zhang_sheng": "[Day Stem Twelve Growth Stages]",
|
|||
|
|
"closing": "—— End of hexagram data. Please interpret according to Liu Yao principles.",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def _get_field_map(language: str) -> dict[str, str]:
|
|||
|
|
if language.startswith("en"):
|
|||
|
|
return _EN_FIELDS
|
|||
|
|
return _ZH_FIELDS
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`build_divination_user_prompt` 签名变为 `build_divination_user_prompt(*, derived: DerivedDivinationData, language: str = "zh-CN")`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Step 4: Runner 调用链传递 language
|
|||
|
|
|
|||
|
|
**文件**: `backend/src/core/agentscope/runtime/runner.py`
|
|||
|
|
|
|||
|
|
1. `_build_worker_input_messages` 增加 `language` 参数并传递给 `build_divination_user_prompt`:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def _build_worker_input_messages(
|
|||
|
|
self,
|
|||
|
|
*,
|
|||
|
|
context_messages: list[Msg],
|
|||
|
|
run_input: RunAgentInput,
|
|||
|
|
derived_divination: DerivedDivinationData | None,
|
|||
|
|
language: str,
|
|||
|
|
) -> list[Msg]:
|
|||
|
|
if derived_divination is not None:
|
|||
|
|
user_text = build_divination_user_prompt(derived=derived_divination, language=language)
|
|||
|
|
else:
|
|||
|
|
user_text, _ = extract_latest_user_payload(run_input)
|
|||
|
|
...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
2. `_execute_worker_step` 调用 `_build_worker_input_messages` 时传入 `language`。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Step 5: 新增/更新测试
|
|||
|
|
|
|||
|
|
**文件**: `backend/tests/unit/test_agentscope_prompts.py`
|
|||
|
|
|
|||
|
|
新增测试用例:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
def test_system_prompt_en_has_english_role_playing() -> None:
|
|||
|
|
"""English system prompt should contain English role playing content."""
|
|||
|
|
prompt = build_system_prompt(
|
|||
|
|
agent_type=AgentType.WORKER,
|
|||
|
|
language="en-US",
|
|||
|
|
llm_config=SystemAgentLLMConfig(),
|
|||
|
|
)
|
|||
|
|
assert "Liu Yao" in prompt or "divination master" in prompt
|
|||
|
|
assert "[Boundaries" in prompt or "Career/Work" in prompt
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_system_prompt_en_safety_is_english() -> None:
|
|||
|
|
"""English safety section should be in English."""
|
|||
|
|
prompt = build_system_prompt(
|
|||
|
|
agent_type=AgentType.WORKER,
|
|||
|
|
language="en-US",
|
|||
|
|
llm_config=SystemAgentLLMConfig(),
|
|||
|
|
)
|
|||
|
|
assert "scope limitation" in prompt
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_system_prompt_zh_cn_role_playing_unchanged() -> None:
|
|||
|
|
"""Chinese system prompt should retain original Chinese role playing."""
|
|||
|
|
prompt = build_system_prompt(
|
|||
|
|
agent_type=AgentType.WORKER,
|
|||
|
|
language="zh-CN",
|
|||
|
|
llm_config=SystemAgentLLMConfig(),
|
|||
|
|
)
|
|||
|
|
assert "六爻解卦师" in prompt
|
|||
|
|
assert "推演公理" in prompt
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_agent_prompt_en_has_english_output_rules() -> None:
|
|||
|
|
"""English agent prompt should contain English output rules."""
|
|||
|
|
prompt = build_agent_prompt(
|
|||
|
|
agent_type=AgentType.WORKER,
|
|||
|
|
language="en-US",
|
|||
|
|
llm_config=SystemAgentLLMConfig(),
|
|||
|
|
)
|
|||
|
|
assert "focus_points" in prompt
|
|||
|
|
assert "opening paragraph must state" in prompt
|
|||
|
|
assert "段间用" not in prompt # No Chinese formatting rules
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_agent_prompt_zh_cn_unchanged() -> None:
|
|||
|
|
"""Chinese agent prompt should remain unchanged."""
|
|||
|
|
prompt = build_agent_prompt(
|
|||
|
|
agent_type=AgentType.WORKER,
|
|||
|
|
language="zh-CN",
|
|||
|
|
llm_config=SystemAgentLLMConfig(),
|
|||
|
|
)
|
|||
|
|
assert "段间用\\n\\n" in prompt
|
|||
|
|
assert "六爻解卦师" in prompt
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_user_prompt_en_has_english_labels() -> None:
|
|||
|
|
"""English user prompt should have English field labels."""
|
|||
|
|
from core.agentscope.prompts.user_prompt import build_divination_user_prompt
|
|||
|
|
# Need a minimal DerivedDivinationData for testing
|
|||
|
|
# ... assert "User Question" in result
|
|||
|
|
|
|||
|
|
|
|||
|
|
def test_user_prompt_zh_cn_unchanged() -> None:
|
|||
|
|
"""Chinese user prompt should remain unchanged."""
|
|||
|
|
from core.agentscope.prompts.user_prompt import build_divination_user_prompt
|
|||
|
|
# ... assert "用户问题" in result
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 验证
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 运行测试
|
|||
|
|
cd backend
|
|||
|
|
uv run pytest tests/unit/test_agentscope_prompts.py -v
|
|||
|
|
|
|||
|
|
# 类型检查
|
|||
|
|
uv run basedpyright src/core/agentscope/
|
|||
|
|
|
|||
|
|
# Lint
|
|||
|
|
uv run ruff check src/core/agentscope/
|
|||
|
|
```
|