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:
|
try:
|
||||||
from prompture.agents import Conversation
|
from prompture.agents import Conversation
|
||||||
from prompture.infra.provider_env import ProviderEnvironment
|
from prompture.infra.provider_env import ProviderEnvironment
|
||||||
|
from prompture.extraction.tools import strip_think_tags, clean_json_text
|
||||||
_HAS_PROMPTURE = True
|
_HAS_PROMPTURE = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_HAS_PROMPTURE = False
|
_HAS_PROMPTURE = False
|
||||||
|
|
@ -121,12 +122,11 @@ class LLMClient:
|
||||||
"""
|
"""
|
||||||
if _HAS_PROMPTURE:
|
if _HAS_PROMPTURE:
|
||||||
content = self._chat_prompture(messages, temperature, max_tokens)
|
content = self._chat_prompture(messages, temperature, max_tokens)
|
||||||
|
return strip_think_tags(content)
|
||||||
else:
|
else:
|
||||||
content = self._chat_openai(messages, temperature, max_tokens, response_format)
|
content = self._chat_openai(messages, temperature, max_tokens, response_format)
|
||||||
|
# Fallback: strip think tags with regex when Prompture is not available
|
||||||
# 部分模型(如MiniMax M2.5)会在content中包含<think>思考内容,需要移除
|
return re.sub(r'<think>[\s\S]*?</think>', '', content).strip()
|
||||||
content = re.sub(r'<think>[\s\S]*?</think>', '', content).strip()
|
|
||||||
return content
|
|
||||||
|
|
||||||
def chat_json(
|
def chat_json(
|
||||||
self,
|
self,
|
||||||
|
|
@ -147,17 +147,18 @@ class LLMClient:
|
||||||
"""
|
"""
|
||||||
if _HAS_PROMPTURE:
|
if _HAS_PROMPTURE:
|
||||||
response = self._chat_prompture(messages, temperature, max_tokens)
|
response = self._chat_prompture(messages, temperature, max_tokens)
|
||||||
|
# Prompture's clean_json_text strips think tags + markdown fences
|
||||||
|
cleaned = clean_json_text(response)
|
||||||
else:
|
else:
|
||||||
response = self._chat_openai(
|
response = self._chat_openai(
|
||||||
messages, temperature, max_tokens,
|
messages, temperature, max_tokens,
|
||||||
response_format={"type": "json_object"},
|
response_format={"type": "json_object"},
|
||||||
)
|
)
|
||||||
|
# Fallback cleaning when Prompture is not available
|
||||||
# 清理markdown代码块标记
|
cleaned = re.sub(r'<think>[\s\S]*?</think>', '', response).strip()
|
||||||
cleaned = response.strip()
|
cleaned = re.sub(r'^```(?:json)?\s*\n?', '', cleaned, flags=re.IGNORECASE)
|
||||||
cleaned = re.sub(r'^```(?:json)?\s*\n?', '', cleaned, flags=re.IGNORECASE)
|
cleaned = re.sub(r'\n?```\s*$', '', cleaned)
|
||||||
cleaned = re.sub(r'\n?```\s*$', '', cleaned)
|
cleaned = cleaned.strip()
|
||||||
cleaned = cleaned.strip()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return json.loads(cleaned)
|
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