Skip to content

AI 策略生成总是失败:DiscoveryContext.set_metadata() 拒绝 AI 生成代码的位置参数调用 #208

Description

@jieshenglu

Describe the bug

问题描述

POST /api/strategies/generate 每次调用都会失败,报错:

strategyV2.generationInvalid
  -> strategyV2.initializeFailed: DiscoveryContext.set_metadata() takes 1 positional argument but 3 were given

系统提示词让大模型使用 context.set_metadata(...),但没有给出精确的函数签名;而运行时实现只接受关键字参数**values)。大模型(我用 DeepSeek deepseek-v4-flash 稳定复现)总是生成位置参数写法 set_metadata("key", "value"),在编译策略时直接抛 TypeError。内置的"自动修复"环节也无法修复,因为报错信息本身没有传达"必须用关键字参数"这个契约。

Steps to reproduce

复现步骤

  1. 用预构建镜像部署(ghcr.io/openbyteinc/quantdinger-backend:latest,2026-08-14 构建)
  2. 配置任意 LLM 提供商(已验证 DeepSeek,模型 deepseek-v4-flash
  3. 登录后调用接口,随便给个提示词:
curl -s -X POST http://127.0.0.1:5000/api/strategies/generate \
  -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" \
  -d '{"prompt":"写一个 BTC/USDT 1小时周期的简单双均线交叉策略。"}'
  1. 返回:
{"code":0,"msg":"strategyV2.generationInvalid","data":{"error":"strategyV2.initializeFailed:DiscoveryContext.set_metadata() takes 1 positional argument but 3 were given"}}

后端日志确认:首次编译失败(3 were given)→ 自动修复 → 修复后的代码再次失败(2 were given):

repairing invalid generated strategy: strategyV2.initializeFailed:DiscoveryContext.set_metadata() takes 1 positional argument but 3 were given
strategy generation failed: strategyV2.initializeFailed:DiscoveryContext.set_metadata() takes 1 positional argument but 2 were given

Expected behavior

预期行为

策略生成应该成功。要么:

  • 运行时接受位置参数写法(set_metadata("direction", "long")),或者
  • 提示词给出精确的关键字签名,让模型第一次就能生成正确代码

Deployment method

Docker Compose

Relevant logs

## 根因分析

两个文件之间存在**契约不一致****1. 提示词文档 —— `backend_api_python/app/services/ai_generation_contracts.py:35`** 只写了:


- Use `context.set_metadata(...)` in `initialize` for stable descriptive metadata such as direction mode and strategy family.


没有给出签名,也没有说明位置参数会被拒绝。而同一份提示词里其他 API 都标注了 "signatures are exact"(精确签名,如 `order(symbol, amount)``get_history(count, ...)`),所以模型很自然地推断成位置参数调用。

**2. 运行时实现 —— `backend_api_python/app/services/strategy_v2/contract.py:153`**:


def set_metadata(self, **values: Any) -> None:
    self.metadata.update(values)


只接受关键字参数。调用 `set_metadata("direction", "long")` 会抛 `TypeError: set_metadata() takes 1 positional argument but 2 were given`

自动修复环节(`_compile_or_repair_generated_strategy`,在 `backend_api_python/app/routes/strategy.py`)把原始报错文本回传给模型,但因为提示词里始终缺少正确的签名,模型再次生成同样的错误写法。

## 建议修复(二选一,或两个都做)

1. **让运行时兼容位置参数**(改动小、风险低,不依赖模型行为):


def set_metadata(self, *args: Any, **values: Any) -> None:
    if len(args) >= 2:
        values.update({args[i]: args[i + 1] for i in range(0, len(args) - 1, 2)})
    elif args:
        values.setdefault("value", args[0])
    self.metadata.update(values)


2. **在提示词里写明精确签名**(帮助所有模型第一次就生成正确代码,减少修复往返):


- Use `context.set_metadata(**values)` in `initialize` for stable descriptive metadata such as direction mode and strategy family. The signature is keyword-only — always pass keyword arguments, e.g. `context.set_metadata(direction="long", family="moving_average")`. Positional arguments are rejected and fail compilation; never write `context.set_metadata("key", "value")`.


## 环境

- 部署方式:方案 A,GHCR 预构建镜像 + Docker Compose(10 个容器全部 healthy)
- 后端镜像:`ghcr.io/openbyteinc/quantdinger-backend:latest`(2026-08-14 构建,与当前 `main` 分支内容一致)
- LLM 提供商:DeepSeek(`deepseek-v4-flash`),API base `https://api.deepseek.com/v1`
- 已确认当前 `main` 分支仍包含 `set_metadata(self, **values)` 和模糊的提示词 —— 上游尚未修复

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions