๊ธฐ๋ฅ ์์ธ ๋ณด๊ณ
09. LLM ์์ด์ ํธ (Planner / Critic / Reporter, vLLM)
๋์ ๋ชจ๋:
AG_src/llm/prompts.py,AG_src/llm/provider.py,AG_src/agents/{base_agent,planner,critic,reporter}.py,AG_src/config/pipeline_config.yaml์ ๋ ๊ท์น: ๋ชจ๋ ์ฃผ์ฅ์file_path:line์ธ์ฉ. ๋ฏธํ์ธ ์ฌํญ์ "๋ฏธ๊ฒ์ฆ"์ผ๋ก ๋ช ์. ๋ณธ ๋ถ์์ ์ฝ๊ธฐ ์ ์ฉ.
โ ๋์ ์๋ฆฌ
1.1 3๊ฐ LLM ์์ด์ ํธ์ ์ญํ (Co-Scientist ๋ฃจํ)
๋ณธ ํ์ดํ๋ผ์ธ์ PyRosetta mutateโdock ๋ฃจํ๋ฅผ LLM์ด "๊ฐ์ค ์ฃผ๋"๋ก ์กฐ์ข ํ๋ Co-Scientist ๊ตฌ์กฐ๋ค. ์ธ ์์ด์ ํธ๊ฐ ๊ฐ iteration์์ ์์ฐจ์ ์ผ๋ก ์๋ํ๋ค.
- PlannerAgent (
AG_src/agents/planner.py:212) โ "์ฐ๊ตฌ ์ค๊ณ/์คํ ๊ธฐํ" (planner.py:226). ๊ฐ iteration์ExperimentPlan(๊ฐ์ค + ํ๋ผ๋ฏธํฐ + ๋ณ์ด ๊ฐ์ด๋)์ ์์ฑยท๊ฐฑ์ ํ๋ค (planner.py:241create_initial_plan,planner.py:335update_plan). - ScientistCriticAgent (
AG_src/agents/critic.py:266) โ "๋นํ์ ๊ฒํ /์์ธ ๋ถ์" (critic.py:285). QC ๊ฒฐ๊ณผ/๋ญํฌ ํ ์ด๋ธ์ ํด์ํด ์คํจ ์ ํ์ ๋ถ๋ฅํ๊ณ ๋ค์ iteration ํ๋ผ๋ฏธํฐ ๋ณ๊ฒฝ(์ต๋ 2๊ฐ)์ ์ ์ํ๋ค (critic.py:297analyze_results). - ReporterAgent (
AG_src/agents/reporter.py:53) โ "์ต์ข ๋ฆฌํฌํธ/๊ทธ๋ฆผ ์๋ํ" (reporter.py:74). iteration ์์ฝ Markdownยทlab notebookยทPyMOL ๋ ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ๋ค (reporter.py:197generate_summary_report).
์ธ ์์ด์ ํธ ๋ชจ๋ BaseAgent(AG_src/agents/base_agent.py:56)๋ฅผ ์์ํ๋ฉฐ, BaseAgent.has_llm(base_agent.py:197)์ผ๋ก LLM ์ฐ๊ฒฐ ์ฌ๋ถ๋ฅผ ํ๋จํ๊ณ llm_generate_json(base_agent.py:221)์ผ๋ก JSON ์๋ต์ ๋ฐ๋๋ค.
1.2 vLLM ๋ฐฑ์๋ + Qwen3-32B no-think
LLM ํธ์ถ์ VLLMProvider(AG_src/llm/provider.py:251)๊ฐ ๋ด๋นํ๋ค.
- ์๋ํฌ์ธํธ: OpenAI ํธํ
POST /v1/chat/completions(provider.py:304). - ๋ชจ๋ธ: ์ค์ ์
qwen3-32b,base_url: http://localhost:8000,temperature: 0.3,max_tokens: 4096,timeout: 120(AG_src/config/pipeline_config.yaml:225-231). - no-think ๊ฐ์ : payload ์ต์์์
chat_template_kwargs.enable_thinking=False๋ฅผ ์ง์ ์ฝ์ ํ๋ค (provider.py:299). ์ด๋ Qwen3 thinking ๋ชจ๋ธ์ดcontent=null+ reasoning๋ง ๋ฐํํ๊ฑฐ๋ ๋ณด์์ ์ผ๋ก ์๋ตํ๋ ํ์(M4 ๋ฒ๊ทธ)์ ๋ฐฉ์งํ๊ธฐ ์ํจ์ด๋ค (provider.py:83-85,provider.py:272-274). ์ค์ ๊ธฐ๋ณธ๊ฐ๋enable_thinking: false(pipeline_config.yaml:232). - thinking์ด ์ผ์ง ๊ฒฝ์ฐ์ ์์ ๋ง:
content๊ฐ ๋น๋ฉดreasoning/reasoning_content๋ก ํด๋ฐฑํ๊ณ , ๋ ๋ค ์์ผ๋ฉด ํ ํฐ ์ด๊ณผ ๊ฐ๋ฅ์ฑ์ ๊ฒฝ๊ณ ํ๋ฉฐNone๋ฐํ (provider.py:327-343).
create_provider(provider.py:351)๊ฐ ํฉํ ๋ฆฌ๋ค. config.llm.provider ๊ฐ์ผ๋ก vllm/ollama/none์ ์ ํํ๋ฉฐ (provider.py:397-420), config=None์ด๋ฉด NoneProvider(provider.py:165)๋ฅผ ๋ฐํํด LLM ์์ด ๊ท์น ๊ธฐ๋ฐ ๋ชจ๋๋ก ์๋ํ๋ค (provider.py:383-384). agent๋ณ override๋ ์ง์: agent_name ์ง์ ์ llm.agents.<name> ์น์
์ด ์์ llm ๊ฐ์ ๋ฎ์ด์ด๋ค (provider.py:386-396). ๋ค๋ง ์ค์ ํ์ผ์์ agents: ๋ธ๋ก์ ํ์ฌ ์ฃผ์ ์ฒ๋ฆฌ๋์ด ์์ด ์ธ ์์ด์ ํธ๊ฐ ๋์ผ ๋ชจ๋ธ(qwen3-32b)์ ๊ณต์ ํ๋ค (pipeline_config.yaml:241-254).
1.3 JSON ์คํค๋ง ๊ฐ์ ์ ํ๋กฌํํธ ๊ตฌ์กฐ
prompts.py๋ ์์ด์ ํธ๋ณ ์์คํ
ํ๋กฌํํธ(SYSTEM_PROMPTS, prompts.py:77)์ ์ถ๋ ฅ JSON ์คํค๋ง(OUTPUT_SCHEMAS, prompts.py:121)๋ฅผ ๋ถ๋ฆฌ ๊ด๋ฆฌํ๋ค.
- JSON ๋ชจ๋:
VLLMProvider.generate๊ฐjson_mode=True์ผ ๋response_format={"type":"json_object"}๋ฅผ ์ค์ ํ๋ค (provider.py:301-302). - ์คํค๋ง ์ฃผ์
: ๊ฐ user ํ๋กฌํํธ ๋์ ํด๋น ์คํค๋ง๋ฅผ
\``json ... code ๋ธ๋ก๋ก ์ฒจ๋ถํ๋ค (์: plannerprompts.py:320-325, criticprompts.py:400-405, reporterprompts.py:574-577`). - planner๋ ๋ ๋ชจ๋๋ฅผ ๊ฐ์ง๋ค โ
default(RFdiffusion/MPNN/ESMFold ํฌํจ,prompts.py:32)์pyrosetta_only(prompts.py:46). ํ์๋mutation_guidance(focus_positions + suggested_mutations)๋ฅผ ๊ฐ์ ํ๊ณ , RFdiffusion ๋ฑ ์ธ๋ถ ๋๊ตฌ ์ธ๊ธ์ ๊ธ์งํ๋ค (prompts.py:50-60, ์คํค๋งprompts.py:122-143). - ํ์ฑ ๊ฒฌ๊ณ ์ฑ: ์๋ต์์
<think>...</think>๋ธ๋ก ์ ๊ฑฐ(_strip_think_blocks,provider.py:427) ํ, ์ง์ json.loadsโ ์คํจ ์ ๋งํฌ๋ค์ด ์ฝ๋๋ธ๋ก/์ค๊ดํธ ์ถ์ถ(_extract_json_block,provider.py:446)๋ก 3๋จ๊ณ ํด๋ฐฑํ๋ค (provider.py:146-151).
1.4 fail-open ํด๋ฐฑ (LLM ์คํจ ์ ๊ท์น ๊ธฐ๋ฐ)
์ธ ์์ด์ ํธ๋ ๋ชจ๋ "LLM ์ฐ์ , ์คํจ ์ ๊ท์น ๊ธฐ๋ฐ" ๊ตฌ์กฐ๋ค.
- Planner: LLM ๊ณํ ์์ฑ ์๋(
planner.py:265-278) โNone์ด๊ฑฐ๋validate_plan์คํจ ์ ๊ท์น ๊ธฐ๋ฐ ๊ธฐ๋ณธ ํ๋ผ๋ฏธํฐ(_DEFAULT_PARAMETERS,planner.py:84)๋ก ํด๋ฐฑ. - Critic:
_analyze_via_llm(critic.py:567)๊ฐNone์ด๋ฉดFAILURE_ACTION_MAP(critic.py:150) ๊ธฐ๋ฐ ๊ท์น ๋ถ์์ผ๋ก ํด๋ฐฑ (critic.py:328-336). - Reporter:
_summarize_via_llm(reporter.py:516)๊ฐNone์ด๋ฉด ํ ํ๋ฆฟ ๊ธฐ๋ฐ Markdown์ผ๋ก ํด๋ฐฑ (reporter.py:222-231). - ์ ์ก ๊ณ์ธต ํ๋ณต๋ ฅ:
_http_post_json(provider.py:46)์ด ์ผ์์ ์ค๋ฅ(URLError/timeout/5xx)์ ๋ํด ์ง์ ๋ฐฑ์คํ ์ฌ์๋(๊ธฐ๋ณธ 1+2ํ,provider.py:42-43), HTTP 4xx๋ ์๊ตฌ ์ค๋ฅ๋ก ์ฆ์ ์ค๋จ (provider.py:65-69). ์ด๋ vLLM ์๊ฐ ์ฅ์ ๊ฐ ์กฐ์ฉํ ๊ท์น ๊ธฐ๋ฐ์ผ๋ก degrade๋๋ ๊ฒ์ ๋ง๊ธฐ ์ํ D4/F18 ๋ณด๊ฐ์ด๋ค (provider.py:39-41).
์ฃผ์(๋ฏธ๊ฒ์ฆ ์ํ): fail-open ๊ตฌ์กฐ์ด๋ฏ๋ก vLLM์ด ๋ค์ด๋์ด๋ ํ์ดํ๋ผ์ธ์ ๋ฉ์ถ์ง ์๊ณ ๊ท์น ๊ธฐ๋ฐ์ผ๋ก ๊ณ์ ๋๋ค. ๋ก๊ทธ ๊ฒฝ๊ณ ๋ ๋จ์ง๋ง(planner.py:276-278 ๋ฑ), "LLM์ด ์ค์ ๋ก ๊ฐ์ค์ ์ฃผ๋ํ๋์ง"๋ ๋ก๊ทธ๋ฅผ ํ์ธํด์ผ ์ ์ ์๋ค โ ์ฝ๋๋ง์ผ๋ก๋ ๋ฏธ๊ฒ์ฆ.
โก ์ํฅ โ ๊ฐ์ค ์ฃผ๋ ํ์
ํต์ฌ ๊ฐ์น๋ "ํ์์ด ๋ฌด์์/๊ทธ๋ฆฌ๋๊ฐ ์๋๋ผ LLM ๊ฐ์ค๋ก ์ ๋๋๋ค"๋ ์ ์ด๋ค.
- Planner๊ฐ falsifiable ๊ฐ์ค์ ๋ช
์ํ๊ณ (
prompts.py:42,prompts.py:57),pyrosetta_only๋ชจ๋์์ ๊ตฌ์ฒด์ ๋ณ์ด ๊ฐ์ด๋(์ด๋ ์์น๋ฅผ ์ด๋ค ์๊ธฐ๋ก)๋ฅผ ์์ฑํด ๋ค์ mutateโdock ๋ผ์ด๋์ ํ์ ๊ณต๊ฐ์ ์ขํ๋ค (prompts.py:126-135). - Critic์ด ๊ฒฐ๊ณผ๋ฅผ 6๊ฐ ์คํจ ์ ํ(structural/sequence/docking/stability/selectivity)์ผ๋ก ๋ถ๋ฅํ๊ณ (
critic.py:72-79, ์์คํ ํ๋กฌํํธprompts.py:98), ์์ธ์ ๋ง๋ ํ๋ผ๋ฏธํฐ/๋ณ์ด ๋ณ๊ฒฝ์ ์ ์ํด ํผ๋๋ฐฑ ๋ฃจํ๋ฅผ ๋ซ๋๋ค. - ์ ํ์ฑ ์ ๋ ฌ(2026-06-10 ๋ณด๊ฐ): planner/critic ์์ชฝ ํ๋กฌํํธ๊ฐ ์บ ํ์ธ์ 1์ฐจ ๋ชฉํ๋ฅผ "๊ฐํ SSTR2 ๊ฒฐํฉ"์ด ์๋๋ผ "SSTR2 ์ ํ์ฑ(ฮmargin>0)"์ผ๋ก ์ฌ์ ์ํ๋ค. planner ์์คํ
ํ๋กฌํํธ๋ SSTR2-๊ณ ์ ์์ญ(ECL2/ECL3/TM5/TM6)๊ณผ ๋ณด์กด ์์น ๋ณด์กด ์ ๋ต์ ์ง์ํ๊ณ (
prompts.py:61-75), critic ์์คํ ํ๋กฌํํธ๋ ฮmarginโค0์ด๋ฉด "์บ ํ์ธ ๋ฏธ์ฑ๊ณต"์ผ๋ก ์ง๋จํ๋ผ๊ณ ์ง์ํ๋ค (prompts.py:86-95). user ํ๋กฌํํธ์๋ in-loop ์ ํ์ฑ ๋ฆฌ๋๋ณด๋๊ฐ ์ฃผ์ ๋๋ค (plannerprompts.py:278-291, criticprompts.py:372-398). ์ด ์ ํธ๋ScientistCriticAgent.execute๊ฐ ์ปจํ ์คํธ์selectivity_leaderboard/best_delta_margin์ ๋ชจ์ ์ ๋ฌํ๋ค (critic.py:550-556).
์ํจ๊ณผ: LLM์ด "ฮmargin์ ์์๋ก ๋ง๋๋ ๋ณ์ด"๋ผ๋ ๊ณผํ์ ๋ชฉํ๋ฅผ ์ง์ ์ถ๋ก ํ๋๋ก ์ค๊ณ๋์ด, ๋จ์ ddG ์ต์ ํ์ ํจ์ (off-target๋ ๊ฐํ๊ฒ ๊ฒฐํฉ)์ ํํผํ๋ ๋ฐฉํฅ์ผ๋ก ํ์์ ํธํฅ์ํจ๋ค.
โข ๊ด๋ จ Action Item โ "ํฐ LLM ๊ฒฐ์ "
์ฌ์ฉ์ ๋ฉ๋ชจ๋ฆฌ(sstr2-goal-decisions)์ "ํฐ LLMยทreal PyRosettaยท์ ๋ฉด ํตํฉ" ๊ฒฐ์ ์ด ๋ณธ ๋ชจ๋์ ๋ฐ์๋์ด ์๋ค.
- ollama qwen3:8b โ vLLM qwen3.5-35b-a3b(MoE Active 3B) โ qwen3-32b๋ก ์
๊ทธ๋ ์ด๋๋ ์ด๋ ฅ์ด ์ค์ ์ฃผ์์ ๊ธฐ๋ก๋จ (
pipeline_config.yaml:220-226). ํ์ฌ ์ด์ ๋ชจ๋ธ์qwen3-32b, GPU2 ์๋น, "~40 tok/s, JSON+no-think ๊ฒ์ฆ๋จ" (pipeline_config.yaml:226). - "ํฐ LLM"์ผ๋ก ์ ํํ๋ฉด์ thinking ๋ชจ๋ ๋นํ์ฑํ๊ฐ ํ์ ์กฐ๊ฑด์ด ๋จ(๋ณด์์ ์๋ตยทcontent null ๋ฐฉ์ง) โ
enable_thinking=false์ ์ฑ ์ผ๋ก ์ฝ๋ยท์ค์ ์์ชฝ์ ๊ณ ์ (provider.py:299,pipeline_config.yaml:232). - agent๋ณ ๋ค๋ฅธ LLM ์ด์ ์ต์
(M3, planner=CoT ๊ฐํ ๋ชจ๋ธ, critic/reporter=๋น ๋ฅธ MoE)์ด ์ฝ๋(
provider.py:386-396)์ ์ค์ ์ฃผ์(pipeline_config.yaml:241-254)์ ์ค๋น๋์ด ์์ผ๋ ํ์ฌ ๋นํ์ฑ(์ฃผ์) โ ํ์ฅ ์ฌ์ง๋ก ์๋ณ๋จ, ํ์ฑํ ์ฌ๋ถ ๋ฏธ๊ฒ์ฆ.
โฃ ์์ฑ๋ ํ๊ฐ
์์ฑ๋: ์ฝ 85%
๊ทผ๊ฑฐ:
| ํญ๋ชฉ | ์ํ | ๊ทผ๊ฑฐ |
|---|---|---|
| 3 ์์ด์ ํธ LLM ํตํฉ | ์๋ฃ | planner/critic/reporter ๋ชจ๋ _*_via_llm ๊ฒฝ๋ก ๊ตฌํ (planner.py:532, critic.py:567, reporter.py:516) |
| vLLM/Ollama/None ํ๋ก๋ฐ์ด๋ | ์๋ฃ | 3์ข
+ ํฉํ ๋ฆฌ (provider.py:165,190,251,351) |
| JSON ์คํค๋ง ๊ฐ์ + ํ์ฑ ํด๋ฐฑ | ์๋ฃ | response_format + 3๋จ๊ณ ์ถ์ถ (provider.py:301, 146-151) |
| no-think + ์ ์ก ์ฌ์๋ | ์๋ฃ | enable_thinking (provider.py:299), ๋ฐฑ์คํ (provider.py:46) |
| fail-open ๊ท์น ๊ธฐ๋ฐ ํด๋ฐฑ | ์๋ฃ | ์ธ ์์ด์ ํธ ์ ๋ถ ํด๋ฐฑ ๊ฒฝ๋ก ๋ณด์ |
| ์ ํ์ฑ in-loop ํผ๋๋ฐฑ | ์๋ฃ | planner/critic ํ๋กฌํํธ + execute ๋ฐฐ์ (prompts.py:278, critic.py:550) |
| agent๋ณ LLM override | ๊ตฌํ๋์ผ๋ ๋นํ์ฑ | ์ฝ๋ ์กด์ฌ(provider.py:386), ์ค์ ์ฃผ์ ์ฒ๋ฆฌ(pipeline_config.yaml:241) |
๊ฐ์ ์ฌ์ (๋ฏธ์/๋ถ์ผ์น):
- Critic LLM ์คํค๋ง์ ์์คํ
ํ๋กฌํํธ์ selectivity ์ฐจ์ ๋ถ์ผ์น(๋ฏธ๊ฒ์ฆ ์ํ): ์์คํ
ํ๋กฌํํธ๋ ์คํจ ์ ํ์
selectivity๋ฅผ ์ถ๊ฐํ๋ผ๊ณ ์ง์(prompts.py:98)ํ๋,OUTPUT_SCHEMAS["critic"].failure_analysis์๋structural/sequence/docking/stability๋ง ์๊ณ selectivity ํ๋๊ฐ ์๋ค (prompts.py:170-175). LLM์ด selectivity๋ฅผ ์ด๋์ ๋ด์์ง ์คํค๋ง์ ๋ชจํธ โ ์ค์ ์๋ต ์ฒ๋ฆฌ ์ํฅ์ ๋ฏธ๊ฒ์ฆ. - planner
default์คํค๋ง์_PYROSETTA_ONLY_STEPS์ ์์กด RFdiffusion ํ์ : default ์คํค๋ง/์คํ ํ ํ๋ฆฟ์๋ ์ฌ์ ํ RFdiffusion/MPNN/ESMFold ๊ตฌ์กฐ๊ฐ ๋จ์ ์๋ค(prompts.py:144-167,planner.py:108-155). ์ด์ ๋ชจ๋๊ฐ pyrosetta_only์ผ ๋๋ง ์ ํฉ โ ๋ชจ๋ ์ค์ ์์น๋ ๋ณธ ๋ถ์ ๋ฒ์ ๋ฐ(๋ฏธ๊ฒ์ฆ). - Reporter ํด๋ฐฑ ๋ณด๊ณ ์์ ๋ชจ๋ธ๋ช
ํ๋์ฝ๋ฉ ์ค๋ฅ: LLM ๋ณด๊ณ ์ ํค๋์ "์์ฑ ๋ฐฉ์: LLM (Qwen 2.5 7B)"๋ก ์๋ชป ๊ธฐ์ฌ(
reporter.py:572). ์ค์ ๋ชจ๋ธ์ qwen3-32b โ ์ฌ์ํ๋ ๋ช ๋ฐฑํ ํ๊ธฐ ๋ฒ๊ทธ. - prompts.py ๋ชจ๋ docstring์ ๋ชจ๋ธ๋ช
๋
ธํํ: "Qwen 2.5 7B / Qwen 3.5-35B-A3B"๋ก ๊ธฐ์ฌ(
prompts.py:4), ํ ์ด์ ๋ชจ๋ธ qwen3-32b์ ๋ถ์ผ์น.
โค ํ์ ๊ฐ์น โ Agentic AI Scientist
- Co-Scientist / AI Scientist ํจ๋ฌ๋ค์ ๊ตฌํ์ฒด: Planner(๊ฐ์ค ์์ฑ)โ์คํ(mutate-dock)โCritic(์์ธ ๋ถ์ยท๋ฐ์ฆ)โReporter(๊ธฐ๋ก)์ ๋ซํ ์์จ ๊ณผํ ๋ฃจํ๋ฅผ LLM์ผ๋ก ๊ตฌ๋ํ๋ค. ์ด๋ "AI๊ฐ ๊ฐ์ค์ ์ธ์ฐ๊ณ ๊ฒ์ฆยท์์ ํ๋" agentic discovery ํ๋ฆ(์: Google Co-Scientist, Sakana AI Scientist ๊ณ์ด)์ ๋๋ฉ์ธ ํนํ ์ ์ฉ์ด๋ค.
- ๊ฒ์ฆ ๊ฐ๋ฅํ ๊ฐ์ค(falsifiability) ๊ฐ์ : ํ๋กฌํํธ๊ฐ "falsifiable hypothesis"์ "๋ค์ iteration์ pLDDT/ddG/๋ํน ๋ถํฌ๋ก ๊ฒ์ฆ"์ ๋ช
์(
prompts.py:42,critic.py:521-523)ํด, ๋จ์ ์์ฑ์ด ์๋๋ผ ๊ณผํ์ ๋ฐฉ๋ฒ๋ก (๊ฐ์ค-๊ฒ์ฆ)์ LLM ์ถ๋ ฅ์ ๊ตฌ์กฐ์ ์ผ๋ก ๋ถ๊ณผํ๋ค. - ํ๊ฐ ๋ฐฉ์ง ์ค๊ณ: JSON ์คํค๋ง ๊ฐ์ , no-think, ๊ท์น ๊ธฐ๋ฐ ํด๋ฐฑ, ์ ํ์ฑ ๊ฐ์ ์ ๋ ๋ชฉํ(ฮmargin) ์ง๊ฒฐ โ LLM์ ๋น๊ฒฐ์ ์ฑ์ ๋๋ฉ์ธ ์ ์ฝ์ผ๋ก ๊ฐ๋๋ ๋ฐฉ์์ "์ ๋ขฐ ๊ฐ๋ฅํ ๊ณผํ ์์ด์ ํธ" ์ฐ๊ตฌ์ ์ฌ๋ก ๊ฐ์น๊ฐ ์๋ค. ํนํ critic ํ๋กฌํํธ๊ฐ "๊ฐํ ddG๊ฐ ๋์ ์ ํ์ฑ์ ๊ฐ๋ฆฌ์ง ์๊ฒ ํ๋ผ"(
prompts.py:94-95)๊ณ ๋ช ์ํ ๊ฒ์ ๋ค๋ชฉ์ ์ต์ ํ์์ LLM judge์ ํจ์ ์ ์ ์ ์ฐจ๋จํ ์ค๊ณ. - ์ฌํ์ฑ/์ถ์ ์ฑ: ๋ณ๊ฒฝ์ ์ต๋ 2๊ฐ๋ก ์ ํ(์์ธ-๊ฒฐ๊ณผ ์ถ์ ,
critic.py:276)ํ๊ณchanges_from_prev๋ฅผ ๊ธฐ๋ก(planner.py:570-574)ํ๋ ๊ฒ์ ์คํ ๋ ธํธ๋ถ ์๋ํ์ ํ์ ์ ๋ชจ๋ฒ ์ฌ๋ก.
โฅ ์ฌ์ฉ๋ฒ
6.1 ํ๋ก๋ฐ์ด๋ ์์ฑ
from AG_src.llm.provider import create_provider
import yaml
config = yaml.safe_load(open("AG_src/config/pipeline_config.yaml"))
provider = create_provider(config) # ์์ llm ์ค์ ์ฌ์ฉ (vllm qwen3-32b)
provider = create_provider(config, agent_name="critic") # agent๋ณ override ์ ์ฉ (ํ์ฑ ์)
provider = create_provider(None) # NoneProvider โ ๊ท์น ๊ธฐ๋ฐ ๋ชจ๋
(์๊ทธ๋์ฒ: provider.py:351)
6.2 ์์ด์ ํธ์ LLM ์ฃผ์
from AG_src.agents.planner import PlannerAgent
planner = PlannerAgent(llm_provider=provider, planner_mode="pyrosetta_only")
plan = planner.create_initial_plan(receptor_config={...}, constraints={...})
# ๋๋ context ๊ธฐ๋ฐ
result = planner.execute({"iteration": 1, "receptor_config": {...}, "constraints": {...}})
(์์ฑ์: planner.py:223, execute: planner.py:501. critic: critic.py:281/critic.py:534, reporter: reporter.py:67/reporter.py:465)
6.3 ์ง์ JSON ์์ฑ / ๋ณ์ด ์์ฑ ํ๋กฌํํธ
from AG_src.llm.prompts import build_variant_generation_prompt, VARIANT_DESIGN_SYSTEM_PROMPT
prompt = build_variant_generation_prompt("AGCKNFFWKTFTSC", [1,2,4,5,6,11,12,13], n_mutations=3)
result = provider.generate_json(prompt, system_prompt=VARIANT_DESIGN_SYSTEM_PROMPT)
(prompts.py:461, prompts.py:445)
6.4 ์ ์ ์กฐ๊ฑด
- vLLM ์๋ฒ๊ฐ
http://localhost:8000์์ qwen3-32b๋ฅผ ์๋น ์ค์ด์ด์ผ ํจ (pipeline_config.yaml:226-227). ๋ฏธ๊ฐ๋ ์ ์๋์ผ๋ก ๊ท์น ๊ธฐ๋ฐ ํด๋ฐฑ. - timeout 120s, max_tokens 4096 (
pipeline_config.yaml:229-231).
โฆ ํ์ ์ด์
- ๋ฌด์์ ํ์์ ๋นํจ์จ ํํผ: SST-14 ๊ฐ๋ณ ์์น 8๊ณณ(
pipeline_config.yaml:196)์ ๋ํ ์กฐํฉ ํญ๋ฐ์ LLM ๊ฐ์ค๋ก ์ขํ, mutateโdock ๊ฐ์ ๊ณ ๋น์ฉ(ํ๋ณด๋น ์ต๋ 1800s,pipeline_config.yaml:209) ํ๊ฐ๋ฅผ ๊ฐ์น ๋์ ๋ณ์ด์ ์ง์ค์ํจ๋ค. - ์ ํ์ฑ์ด๋ผ๋ ๋ค๋ชฉ์ ํจ์ ํด๊ฒฐ: ddG๋ง ์ต์ ํํ๋ฉด native SST-14์ฒ๋ผ pan-agonist๊ฐ ๋์ด๋ฒ๋ฆฌ๋ ํจ์ ์, "ฮmargin์ ์์๋ก"๋ผ๋ ๋ช
์์ ๋ชฉํ๋ฅผ LLM์ ๋ถ๊ณผํด ํํผํ๋ค (
prompts.py:61-75,prompts.py:86-95). - ์์จ ์คํ ๋ฃจํ์ ๋๋: ์ฝ๋ ๊ธฐ๋ฐ ์์ด์ ํธ(qc_ranker, diversity_manager, builder,
pipeline_config.yaml:234)๋ "์คํ"์ ๋ด๋นํ๊ณ , LLM ์์ด์ ํธ๋ "์/๋ฌด์์ ๋ค์์"๋ผ๋ ์์ฌ๊ฒฐ์ ์ ๋ด๋นํ๋ค โ Co-Scientist ๋ถ์ ์ ํต์ฌ ๋๋ ์ญํ . - ์ด์ ์์ ์ฑ: vLLM ์ฅ์ ยทํ ํฐ ์ด๊ณผยทJSON ๊นจ์ง์๋ ํ์ดํ๋ผ์ธ์ด ๋ฉ์ถ์ง ์๋๋ก fail-open + ์ฌ์๋ + ๋ค๋จ๊ณ ํ์ฑ์ ๊ฐ์ถฐ, ๋ฌดํ ๋ฐ๊ตด ์์ง(๋ฉ๋ชจ๋ฆฌ
sstr2-selectivity-goal) ๊ฐ์ ์ฅ๊ธฐ ๋ฌด์ธ ์ด์์ ๊ฐ๋ฅ์ผ ํ๋ค.
๊ฒ์ฆ ์ธ์ฉ ๋ชฉ๋ก
AG_src/llm/provider.py:46-82โ_http_post_json๋ฐฑ์คํ ์ฌ์๋, 4xx ์๊ตฌ ์ค๋ฅ ์ฒ๋ฆฌAG_src/llm/provider.py:122-151โgenerate_json, think ๋ธ๋ก ์ ๊ฑฐ + JSON ํด๋ฐฑAG_src/llm/provider.py:165-183โNoneProvider(๊ท์น ๊ธฐ๋ฐ ๋ชจ๋)AG_src/llm/provider.py:251-344โVLLMProvider,enable_thinking, content/reasoning ํด๋ฐฑAG_src/llm/provider.py:299โchat_template_kwargs.enable_thinkingpayload ์ฃผ์AG_src/llm/provider.py:301-302โresponse_formatJSON ๋ชจ๋AG_src/llm/provider.py:351-420โcreate_providerํฉํ ๋ฆฌ + agent overrideAG_src/llm/provider.py:427-470โ_strip_think_blocks,_extract_json_blockAG_src/llm/prompts.py:32-75โ planner default / pyrosetta_only ์์คํ ํ๋กฌํํธ (์ ํ์ฑ ๊ฐ์ด๋)AG_src/llm/prompts.py:80-113โ critic / reporter ์์คํ ํ๋กฌํํธ (์ ํ์ฑ ์ ๋ ฌ)AG_src/llm/prompts.py:121-205โOUTPUT_SCHEMAS(4์ข JSON ์คํค๋ง)AG_src/llm/prompts.py:228-327โformat_planner_prompt(+ ์ ํ์ฑ ๋ฆฌ๋๋ณด๋ ์ฃผ์ )AG_src/llm/prompts.py:330-407โformat_critic_prompt(+ ์ ํ์ฑ ์น์ )AG_src/llm/prompts.py:445-532โVARIANT_DESIGN_SYSTEM_PROMPT,build_variant_generation_promptAG_src/llm/prompts.py:535-579โformat_reporter_promptAG_src/agents/base_agent.py:56-239โBaseAgent,has_llm,llm_generate_jsonAG_src/agents/planner.py:212-613โPlannerAgent, LLM ๋ถ๊ธฐ + ๊ท์น ํด๋ฐฑ + sanitizeAG_src/agents/critic.py:150-259โFAILURE_ACTION_MAP(๊ท์น ๊ธฐ๋ฐ ํด๋ฐฑ)AG_src/agents/critic.py:266-634โScientistCriticAgent,_analyze_via_llm, ์ ํ์ฑ ๋ฐฐ์AG_src/agents/reporter.py:53-586โReporterAgent,_summarize_via_llm, ํด๋ฐฑ ํ ํ๋ฆฟAG_src/agents/reporter.py:572โ ๋ชจ๋ธ๋ช ํ๊ธฐ ์ค๋ฅ ("Qwen 2.5 7B")AG_src/config/pipeline_config.yaml:219-254โ LLM ์ค์ (vllm qwen3-32b, enable_thinking false, agent override ์ฃผ์)