增加本地 call llm
This commit is contained in:
@@ -3,6 +3,7 @@ import time
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import json
|
import json
|
||||||
|
import anthropic
|
||||||
|
|
||||||
|
|
||||||
def fetch_llm_generate_task(odoo_base_url="http://localhost:8069"):
|
def fetch_llm_generate_task(odoo_base_url="http://localhost:8069"):
|
||||||
@@ -80,8 +81,9 @@ def call_llm_generate(task_data, max_retries=3):
|
|||||||
str: 生成的内容,如果失败返回 "failed"
|
str: 生成的内容,如果失败返回 "failed"
|
||||||
"""
|
"""
|
||||||
if task_data is None:
|
if task_data is None:
|
||||||
print("[ERROR] task_data 为 None,无法调用 LLM")
|
error_msg = "[ERROR] task_data 为 None,无法调用 LLM"
|
||||||
return "failed"
|
print(error_msg)
|
||||||
|
return error_msg
|
||||||
|
|
||||||
# 提取 task_data 中的字段
|
# 提取 task_data 中的字段
|
||||||
final_prompt = task_data.get('final_prompt', '')
|
final_prompt = task_data.get('final_prompt', '')
|
||||||
@@ -153,6 +155,124 @@ def call_llm_generate(task_data, max_retries=3):
|
|||||||
return "failed"
|
return "failed"
|
||||||
|
|
||||||
|
|
||||||
|
def call_llm_generate_with_anthropic(task_data, max_retries=3):
|
||||||
|
"""
|
||||||
|
调用 MiniMax 的 Anthropic 兼容接口生成内容
|
||||||
|
|
||||||
|
Args:
|
||||||
|
task_data: 包含 final_prompt, system_prompt, user_prompt 的字典
|
||||||
|
max_retries: 最大重试次数,默认 3 次(针对非529错误)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: 生成的内容,如果失败返回 "failed"
|
||||||
|
"""
|
||||||
|
if task_data is None:
|
||||||
|
error_msg = "[ERROR] task_data 为 None,无法调用 LLM"
|
||||||
|
print(error_msg)
|
||||||
|
return error_msg
|
||||||
|
|
||||||
|
# 提取 task_data 中的字段
|
||||||
|
final_prompt = task_data.get('final_prompt', '')
|
||||||
|
system_prompt = task_data.get('system_prompt', '')
|
||||||
|
user_prompt = task_data.get('user_prompt', '')
|
||||||
|
record_id = task_data.get('id', 'unknown')
|
||||||
|
|
||||||
|
print(f"[INFO] 开始为 record_id={record_id} 调用 MiniMax Anthropic 接口")
|
||||||
|
|
||||||
|
# 配置 Anthropic 客户端
|
||||||
|
ANTHROPIC_API_KEY = "sk-cp-l_as8mjqPhsOIny9IFKZ8jzA92z1c0eRwchldhEf4KzQjs9cjVknV2o7VNCcvYUXsXFq7uF4aSgp2RxxmUHLXwPGKgIvzedM70_XUIXiBB3gu_UmLDQLfh4"
|
||||||
|
ANTHROPIC_BASE_URL = "https://api.minimaxi.com/anthropic"
|
||||||
|
|
||||||
|
client = anthropic.Anthropic(
|
||||||
|
api_key=ANTHROPIC_API_KEY,
|
||||||
|
base_url=ANTHROPIC_BASE_URL
|
||||||
|
)
|
||||||
|
|
||||||
|
# 针对 529 错误的专门重试机制
|
||||||
|
MAX_RETRIES_529 = 30 # 529 错误最大重试次数
|
||||||
|
RETRY_DELAY_529 = 10 # 529 错误重试间隔(秒)
|
||||||
|
|
||||||
|
total_retry = 1
|
||||||
|
for attempt_529 in range(1, MAX_RETRIES_529 + 1):
|
||||||
|
# 普通错误的重试机制
|
||||||
|
for attempt in range(1, max_retries + 1):
|
||||||
|
try:
|
||||||
|
print(f"[INFO] 第 {total_retry} 次尝试调用 MiniMax...")
|
||||||
|
total_retry += 1
|
||||||
|
|
||||||
|
# 构建消息列表
|
||||||
|
messages = []
|
||||||
|
|
||||||
|
# 如果有 final_prompt 或 user_prompt,作为用户消息
|
||||||
|
user_content = final_prompt if final_prompt else user_prompt
|
||||||
|
if user_content:
|
||||||
|
messages.append({
|
||||||
|
"role": "user",
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": user_content
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
# 调用 API(使用流式传输,因为操作可能超过 10 分钟)
|
||||||
|
generated_content = ""
|
||||||
|
with client.messages.stream(
|
||||||
|
model="MiniMax-M2.7",
|
||||||
|
system=system_prompt if system_prompt else "You are a helpful assistant.",
|
||||||
|
messages=messages,
|
||||||
|
max_tokens=32768
|
||||||
|
) as stream:
|
||||||
|
for text in stream.text_stream:
|
||||||
|
generated_content += text
|
||||||
|
|
||||||
|
# 检查是否有思考过程(流式模式下通常不会返回 thinking 块)
|
||||||
|
if hasattr(stream, 'thinking') and stream.thinking:
|
||||||
|
print(f"[DEBUG] 思考过程: {stream.thinking[:100]}...")
|
||||||
|
|
||||||
|
if generated_content:
|
||||||
|
print(f"[SUCCESS] 第 {attempt} 次尝试成功,生成长度: {len(generated_content)} 字符")
|
||||||
|
return generated_content
|
||||||
|
else:
|
||||||
|
print(f"[WARNING] 第 {attempt} 次尝试返回空内容")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# 检查是否是 529 错误
|
||||||
|
error_str = str(e)
|
||||||
|
if "529" in error_str or "overloaded" in error_str.lower():
|
||||||
|
print(f"[WARNING] 遇到服务器拥挤 (529) 错误: {e}")
|
||||||
|
# 跳出内层循环,进入外层 529 重试逻辑
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print(f"[ERROR] 第 {attempt} 次尝试发生错误: {e}")
|
||||||
|
|
||||||
|
# 如果不是最后一次尝试,等待后继续(普通错误重试)
|
||||||
|
if attempt < max_retries:
|
||||||
|
print(f"[INFO] 等待 2 秒后重试...")
|
||||||
|
time.sleep(2)
|
||||||
|
else:
|
||||||
|
# 内层循环正常结束(没有 break),说明没有遇到 529 错误且重试用完
|
||||||
|
# 所有重试都失败了
|
||||||
|
error_msg = f"[FAILED] 经过 {max_retries} 次尝试后仍然失败"
|
||||||
|
print(error_msg)
|
||||||
|
return error_msg
|
||||||
|
|
||||||
|
# 执行到这里说明遇到了 529 错误,进行外层重试
|
||||||
|
if attempt_529 < MAX_RETRIES_529:
|
||||||
|
print(f"[INFO] 遇到服务器拥挤 (529),第 {attempt_529}/{MAX_RETRIES_529} 次重试,等待 {RETRY_DELAY_529} 秒...")
|
||||||
|
time.sleep(RETRY_DELAY_529)
|
||||||
|
else:
|
||||||
|
error_msg = f"[FAILED] 经过 {MAX_RETRIES_529} 次 529 重试后仍然失败"
|
||||||
|
print(error_msg)
|
||||||
|
return error_msg
|
||||||
|
|
||||||
|
# 所有重试都失败了
|
||||||
|
error_msg = f"[FAILED] 经过 {MAX_RETRIES_529} 次 529 重试后仍然失败"
|
||||||
|
print(error_msg)
|
||||||
|
return error_msg
|
||||||
|
|
||||||
|
|
||||||
def upload_llm_result(odoo_base_url, upload_data):
|
def upload_llm_result(odoo_base_url, upload_data):
|
||||||
"""
|
"""
|
||||||
上传 LLM 生成结果到 Odoo
|
上传 LLM 生成结果到 Odoo
|
||||||
@@ -168,36 +288,45 @@ def upload_llm_result(odoo_base_url, upload_data):
|
|||||||
Returns:
|
Returns:
|
||||||
bool: 上传成功返回 True,失败返回 False
|
bool: 上传成功返回 True,失败返回 False
|
||||||
"""
|
"""
|
||||||
|
# 构建上传结果的 API URL
|
||||||
url = f"{odoo_base_url}/api/alpha-idea/result"
|
url = f"{odoo_base_url}/api/alpha-idea/result"
|
||||||
|
|
||||||
|
# 设置请求头,指定内容类型为 JSON
|
||||||
headers = {
|
headers = {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
# 打印上传信息日志
|
||||||
print(f"[INFO] 正在上传结果到 Odoo: {url}")
|
print(f"[INFO] 正在上传结果到 Odoo: {url}")
|
||||||
print(f"[INFO] 上传数据: {json.dumps(upload_data, ensure_ascii=False)}")
|
print(f"[INFO] 上传数据: {json.dumps(upload_data, ensure_ascii=False)}")
|
||||||
|
|
||||||
|
# 发送 POST 请求,设置超时时间为 30 秒
|
||||||
response = httpx.post(
|
response = httpx.post(
|
||||||
url,
|
url,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json=upload_data,
|
json=upload_data,
|
||||||
timeout=30
|
timeout=30
|
||||||
)
|
)
|
||||||
|
# 如果 HTTP 状态码表示错误,则抛出异常
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
|
# 解析响应结果
|
||||||
result = response.json()
|
result = response.json()
|
||||||
print(f"[INFO] 上传结果接口返回: {json.dumps(result, ensure_ascii=False)}")
|
print(f"[INFO] 上传结果接口返回: {json.dumps(result, ensure_ascii=False)}")
|
||||||
|
|
||||||
# 检查返回结果
|
# 检查返回结果是否成功
|
||||||
if isinstance(result, dict):
|
if isinstance(result, dict):
|
||||||
|
# 判断返回状态是否为成功
|
||||||
if result.get('status') == 'success' or result.get('success') is True:
|
if result.get('status') == 'success' or result.get('success') is True:
|
||||||
print(f"[SUCCESS] 结果上传成功")
|
print(f"[SUCCESS] 结果上传成功")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# 如果返回结果不符合预期,打印警告信息
|
||||||
print(f"[WARNING] 结果上传可能失败: {result}")
|
print(f"[WARNING] 结果上传可能失败: {result}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# 处理各种异常情况
|
||||||
except httpx.TimeoutException:
|
except httpx.TimeoutException:
|
||||||
print("[ERROR] 上传结果超时")
|
print("[ERROR] 上传结果超时")
|
||||||
return False
|
return False
|
||||||
@@ -218,6 +347,9 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
print("开始获取 LLM 生成任务...")
|
print("开始获取 LLM 生成任务...")
|
||||||
|
|
||||||
|
# 这里我手动控制就行
|
||||||
|
llm_select = 0
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
# 获取任务数据
|
# 获取任务数据
|
||||||
task_data = fetch_llm_generate_task(odoo_base_url=ODOO_BASE_URL)
|
task_data = fetch_llm_generate_task(odoo_base_url=ODOO_BASE_URL)
|
||||||
@@ -225,11 +357,20 @@ if __name__ == "__main__":
|
|||||||
if not task_data:
|
if not task_data:
|
||||||
break
|
break
|
||||||
|
|
||||||
llm_generate_result = call_llm_generate(task_data)
|
if llm_select == 1:
|
||||||
|
llm_generate_result = call_llm_generate(task_data)
|
||||||
|
else:
|
||||||
|
llm_generate_result = call_llm_generate_with_anthropic(task_data)
|
||||||
|
|
||||||
print(llm_generate_result)
|
if not llm_generate_result:
|
||||||
|
continue
|
||||||
|
|
||||||
if llm_generate_result != "failed":
|
print(llm_generate_result[:100])
|
||||||
|
|
||||||
|
# 检查是否成功:如果结果以 [ERROR] 或 [FAILED] 开头,说明失败了
|
||||||
|
is_failed = llm_generate_result.startswith('[ERROR]') or llm_generate_result.startswith('[FAILED]')
|
||||||
|
|
||||||
|
if not is_failed:
|
||||||
print("开始上传 LLM 生成结果...")
|
print("开始上传 LLM 生成结果...")
|
||||||
upload_data = {
|
upload_data = {
|
||||||
'record_id': task_data['id'],
|
'record_id': task_data['id'],
|
||||||
@@ -242,7 +383,7 @@ if __name__ == "__main__":
|
|||||||
'record_id': task_data['id'],
|
'record_id': task_data['id'],
|
||||||
'status': 'failed',
|
'status': 'failed',
|
||||||
'result': '',
|
'result': '',
|
||||||
'error_message': 'generate failed'
|
'error_message': llm_generate_result
|
||||||
}
|
}
|
||||||
|
|
||||||
# 上传结果到 Odoo
|
# 上传结果到 Odoo
|
||||||
@@ -252,5 +393,4 @@ if __name__ == "__main__":
|
|||||||
else:
|
else:
|
||||||
print("[FAILED] 结果上传失败")
|
print("[FAILED] 结果上传失败")
|
||||||
|
|
||||||
time.sleep(60)
|
time.sleep(60)
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import anthropic
|
||||||
|
|
||||||
|
|
||||||
|
client = anthropic.Anthropic(
|
||||||
|
api_key="sk-cp-l_as8mjqPhsOIny9IFKZ8jzA92z1c0eRwchldhEf4KzQjs9cjVknV2o7VNCcvYUXsXFq7uF4aSgp2RxxmUHLXwPGKgIvzedM70_XUIXiBB3gu_UmLDQLfh4",
|
||||||
|
base_url="https://api.minimaxi.com/anthropic"
|
||||||
|
)
|
||||||
|
|
||||||
|
message = client.messages.create(
|
||||||
|
model="MiniMax-M2.7",
|
||||||
|
max_tokens=1000,
|
||||||
|
system="You are a helpful assistant.",
|
||||||
|
messages=[{"role": "user", "content": [{"type": "text", "text": "Hi, how are you?"}]}]
|
||||||
|
)
|
||||||
|
|
||||||
|
for block in message.content:
|
||||||
|
if block.type == "thinking":
|
||||||
|
print(f"Thinking:\n{block.thinking}\n")
|
||||||
|
elif block.type == "text":
|
||||||
|
print(f"Text:\n{block.text}\n")
|
||||||
Reference in New Issue
Block a user