fix: use Prompture's strip_think_tags and clean_json_text instead of hand-rolled regexes
chat() and chat_json() now delegate think-tag stripping and JSON cleanup to Prompture's built-in utilities (strip_think_tags, clean_json_text). Manual regexes are kept only in the OpenAI fallback path. Adds LM Studio integration test script. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
79edc61563
commit
25909ccdca
|
|
@ -16,6 +16,7 @@ from ..config import Config
|
|||
try:
|
||||
from prompture.agents import Conversation
|
||||
from prompture.infra.provider_env import ProviderEnvironment
|
||||
from prompture.extraction.tools import strip_think_tags, clean_json_text
|
||||
_HAS_PROMPTURE = True
|
||||
except ImportError:
|
||||
_HAS_PROMPTURE = False
|
||||
|
|
@ -121,12 +122,11 @@ class LLMClient:
|
|||
"""
|
||||
if _HAS_PROMPTURE:
|
||||
content = self._chat_prompture(messages, temperature, max_tokens)
|
||||
return strip_think_tags(content)
|
||||
else:
|
||||
content = self._chat_openai(messages, temperature, max_tokens, response_format)
|
||||
|
||||
# 部分模型(如MiniMax M2.5)会在content中包含<think>思考内容,需要移除
|
||||
content = re.sub(r'<think>[\s\S]*?</think>', '', content).strip()
|
||||
return content
|
||||
# Fallback: strip think tags with regex when Prompture is not available
|
||||
return re.sub(r'<think>[\s\S]*?</think>', '', content).strip()
|
||||
|
||||
def chat_json(
|
||||
self,
|
||||
|
|
@ -147,17 +147,18 @@ class LLMClient:
|
|||
"""
|
||||
if _HAS_PROMPTURE:
|
||||
response = self._chat_prompture(messages, temperature, max_tokens)
|
||||
# Prompture's clean_json_text strips think tags + markdown fences
|
||||
cleaned = clean_json_text(response)
|
||||
else:
|
||||
response = self._chat_openai(
|
||||
messages, temperature, max_tokens,
|
||||
response_format={"type": "json_object"},
|
||||
)
|
||||
|
||||
# 清理markdown代码块标记
|
||||
cleaned = response.strip()
|
||||
cleaned = re.sub(r'^```(?:json)?\s*\n?', '', cleaned, flags=re.IGNORECASE)
|
||||
cleaned = re.sub(r'\n?```\s*$', '', cleaned)
|
||||
cleaned = cleaned.strip()
|
||||
# Fallback cleaning when Prompture is not available
|
||||
cleaned = re.sub(r'<think>[\s\S]*?</think>', '', response).strip()
|
||||
cleaned = re.sub(r'^```(?:json)?\s*\n?', '', cleaned, flags=re.IGNORECASE)
|
||||
cleaned = re.sub(r'\n?```\s*$', '', cleaned)
|
||||
cleaned = cleaned.strip()
|
||||
|
||||
try:
|
||||
return json.loads(cleaned)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
"""
|
||||
Quick test: MiroFish LLMClient → LM Studio via Prompture
|
||||
"""
|
||||
import sys, os
|
||||
|
||||
# Add backend to path so we can import app modules
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
# Override env vars for LM Studio before Config loads
|
||||
os.environ["LLM_MODEL_NAME"] = "lmstudio/deepseek/deepseek-r1-0528-qwen3-8b"
|
||||
os.environ["LLM_BASE_URL"] = "http://localhost:1234/v1"
|
||||
os.environ["LLM_API_KEY"] = "lm-studio"
|
||||
# Provide a dummy ZEP key so Config.validate() won't complain
|
||||
os.environ.setdefault("ZEP_API_KEY", "dummy")
|
||||
|
||||
from app.utils.llm_client import LLMClient
|
||||
|
||||
def test_basic_chat():
|
||||
print("=== Test 1: Basic chat ===")
|
||||
client = LLMClient()
|
||||
from app.utils.llm_client import _HAS_PROMPTURE
|
||||
print(f" Backend: Prompture={_HAS_PROMPTURE}")
|
||||
print(f" Model: {client.model}")
|
||||
response = client.chat([
|
||||
{"role": "system", "content": "You are a helpful assistant. Reply in one sentence."},
|
||||
{"role": "user", "content": "What is social media simulation?"},
|
||||
], temperature=0.5, max_tokens=256)
|
||||
print(f" Response: {response[:300]}")
|
||||
print()
|
||||
|
||||
def test_json_chat():
|
||||
print("=== Test 2: JSON response ===")
|
||||
client = LLMClient()
|
||||
result = client.chat_json([
|
||||
{"role": "system", "content": "You are a JSON-only assistant. Always respond with valid JSON."},
|
||||
{"role": "user", "content": 'Return a JSON object with keys "platform" and "agents" (an integer). Example: {"platform":"twitter","agents":5}'},
|
||||
], temperature=0.2, max_tokens=256)
|
||||
print(f" Parsed JSON: {result}")
|
||||
print(f" Type: {type(result)}")
|
||||
print()
|
||||
|
||||
def test_multi_turn():
|
||||
print("=== Test 3: Multi-turn conversation ===")
|
||||
client = LLMClient()
|
||||
r1 = client.chat([
|
||||
{"role": "user", "content": "My name is MiroFish. Remember it."},
|
||||
], max_tokens=128)
|
||||
print(f" Turn 1: {r1[:200]}")
|
||||
|
||||
r2 = client.chat([
|
||||
{"role": "user", "content": "My name is MiroFish. Remember it."},
|
||||
{"role": "assistant", "content": r1},
|
||||
{"role": "user", "content": "What is my name?"},
|
||||
], max_tokens=128)
|
||||
print(f" Turn 2: {r2[:200]}")
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"Prompture installed: True")
|
||||
print(f"LM Studio endpoint: http://localhost:1234/v1\n")
|
||||
try:
|
||||
test_basic_chat()
|
||||
test_json_chat()
|
||||
test_multi_turn()
|
||||
print("All tests passed!")
|
||||
except Exception as e:
|
||||
print(f"ERROR: {e}")
|
||||
import traceback; traceback.print_exc()
|
||||
Loading…
Reference in New Issue