You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

9 lines
146 KiB

<!doctypehtml><html lang=zh-CN><meta charset=UTF-8><meta content=width=device-width name=viewport><meta content=#222 name=theme-color><meta content="Hexo 7.1.0" name=generator><link href=https://fonts.googleapis.com rel=preconnect><link href=https://cdnjs.cloudflare.com rel=preconnect><link href=/images/apple-touch-icon-next.png rel=apple-touch-icon sizes=180x180><link href=/images/favicon-32x32-next.png rel=icon sizes=32x32 type=image/png><link href=/images/favicon-16x16-next.png rel=icon sizes=16x16 type=image/png><link color=#222 href=/images/logo.svg rel=mask-icon><meta content=2X6S9P7CAjXjVvw8YyQR8pCu-B0oEu7O9quLgxXuWyA name=google-site-verification><meta content=dV8JGNzi0c name=baidu-site-verification><script>setTimeout(function(){var d=document.createElement("script");d.setAttribute("data-ad-client","ca-pub-7480618470784058"),d.async=!0,d.src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js",document.body.appendChild(d)},5e3),window.addEventListener?window.addEventListener("load",downloadJsAtOnload,!1):window.attachEvent?window.attachEvent("onload",downloadJsAtOnload):window.onload=downloadJsAtOnload</script><style>:root{--body-bg-color:#f5f7f9;--content-bg-color:#fff;--card-bg-color:#f5f5f5;--text-color:#555;--blockquote-color:#666;--link-color:#555;--link-hover-color:#222;--brand-color:#fff;--brand-hover-color:#fff;--table-row-odd-bg-color:#f9f9f9;--table-row-hover-bg-color:#f5f5f5;--menu-item-bg-color:#f5f5f5;--theme-color:#222;--btn-default-bg:#fff;--btn-default-color:#555;--btn-default-border-color:#555;--btn-default-hover-bg:#222;--btn-default-hover-color:#fff;--btn-default-hover-border-color:#222;--highlight-background:#f3f3f3;--highlight-foreground:#444;--highlight-gutter-background:#e1e1e1;--highlight-gutter-foreground:#555;color-scheme:light}html{line-height:1.15;-webkit-text-size-adjust:100%}details,main{display:block}pre{font-size:1em;overflow:auto;padding:10px}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:ButtonText dotted 1px}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}.table-container,textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}summary{display:list-item}[hidden],template{display:none}::selection{background:#262a30;color:#eee}body,html{height:100%}body{margin:0;background:var(--body-bg-color);box-sizing:border-box;color:var(--text-color);font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;font-size:1.2em;line-height:2;min-height:100%;position:relative;transition:padding .2s ease-in-out}h1,h2,h3,h4,h5,h6{font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;font-weight:700;line-height:1.5;margin:30px 0 15px}h1{font-size:1.5em}h2{font-size:1.375em}h3{font-size:1.25em}h4{font-size:1.125em}h5{font-size:1em}h6{font-size:.875em}p{margin:0 0 20px}a{background:0 0;border-bottom:1px solid #999;color:var(--link-color);cursor:pointer;outline:0;text-decoration:none;overflow-wrap:break-word}a:hover{border-bottom-color:var(--link-hover-color);color:var(--link-hover-color)}embed,iframe,img,video{display:block;margin-left:auto;margin-right:auto;max-width:100%}hr{box-sizing:content-box;overflow:visible;background-image:repeating-linear-gradient(-45deg,#ddd,#ddd 4px,transparent 4px,transparent 8px);border:0;height:3px;margin:40px 0}blockquote{border-left:4px solid #ddd;color:var(--blockquote-color);margin:0;padding:0 15px}blockquote cite::before{content:'-';padding:0 5px}dt{font-weight:700}dd{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0;font-size:.875em;margin:0 0 20px;width:100%}tbody tr:nth-of-type(odd){background:var(--table-row-odd-bg-color)}tbody tr:hover{background:var(--table-row-hover-bg-color)}caption,td,th{padding:8px}td,th{border:1px solid #ddd;border-bottom:3px solid #ddd}th{font-weight:700;padding-bottom:10px}td{border-bottom-width:1px}.btn{background:var(--btn-default-bg);border:2px solid var(--btn-default-border-color);border-radius:2px;color:var(--btn-default-color);display:inline-block;font-size:.875em;line-height:2;padding:0 20px;transition:background-color .2s ease-in-out}.btn:hover{background:var(--btn-default-hover-bg);border-color:var(--btn-default-hover-border-color);color:var(--btn-default-hover-color)}.btn+.btn{margin:0 0 8px 8px}.btn .fa-fw{text-align:left;width:1.285714285714286em}.toggle{line-height:0}.toggle .toggle-line{background:#fff;display:block;height:2px;left:0;position:relative;top:0;transition:.4s;width:100%}.toggle .toggle-line:first-child{margin-top:1px}.toggle .toggle-line:not(:first-child){margin-top:4px}.toggle.toggle-arrow :first-child{left:50%;top:2px;transform:rotate(45deg);width:50%}.toggle.toggle-arrow :last-child{left:50%;top:-2px;transform:rotate(-45deg);width:50%}.toggle.toggle-close :nth-child(2){opacity:0}.toggle.toggle-close :first-child{top:6px;transform:rotate(45deg)}.toggle.toggle-close :last-child{top:-6px;transform:rotate(-45deg)}/*!
Theme: Default
Description: Original highlight.js style
Author: (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
Maintainer: @highlightjs/core-team
Website: https://highlightjs.org/
License: see project LICENSE
Touched: 2021
*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.code-container:hover .copy-btn,.highlight:hover .copy-btn{opacity:1}.code-container{position:relative}.copy-btn{color:#333;cursor:pointer;line-height:1.6;opacity:0;padding:2px 6px;position:absolute;transition:opacity .2s ease-in-out;background-color:#eee;background-image:linear-gradient(#fcfcfc,#eee);border:1px solid #d5d5d5;border-radius:3px;font-size:.8125em;right:4px;top:8px}code,figure.highlight,kbd,pre{background:var(--highlight-background);color:var(--highlight-foreground)}figure.highlight,pre{line-height:1.6;margin:0 auto 20px}figure.highlight figcaption,pre .caption,pre figcaption{background:var(--highlight-gutter-background);color:var(--highlight-foreground);display:flow-root;font-size:.875em;line-height:1.2;padding:.5em}figure.highlight figcaption a,pre .caption a,pre figcaption a{color:var(--highlight-foreground);float:right}figure.highlight figcaption a:hover,pre .caption a:hover,pre figcaption a:hover{border-bottom-color:var(--highlight-foreground)}code,pre{font-family:consolas,Menlo,monospace,'PingFang SC','Microsoft YaHei'}code{border-radius:3px;font-size:.875em;padding:2px 4px;overflow-wrap:break-word}kbd{border:2px solid #ccc;border-radius:.2em;box-shadow:.1em .1em .2em rgba(0,0,0,.1);font-family:inherit;padding:.1em .3em;white-space:nowrap}figure.highlight{overflow:auto;position:relative}figure.highlight pre{border:0;margin:0;padding:10px 0}figure.highlight table{border:0;margin:0;width:auto}figure.highlight td{border:0;padding:0}figure.highlight .gutter{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none}figure.highlight .gutter pre{background:var(--highlight-gutter-background);color:var(--highlight-gutter-foreground);padding-left:10px;padding-right:10px;text-align:right}figure.highlight .code pre{padding-left:10px;width:100%}figure.highlight .marked{background:rgba(0,0,0,.3)}pre .caption,pre figcaption{margin-bottom:10px}.gist table{width:auto}.gist table td{border:0}pre code{background:0 0;padding:0;text-shadow:none}.blockquote-center{border-left:0;margin:40px 0;padding:0;position:relative;text-align:center}.blockquote-center::after,.blockquote-center::before{left:0;line-height:1;opacity:.6;position:absolute;width:100%}.blockquote-center::before{border-top:1px solid #ccc;text-align:left;top:-20px;content:'\f10d';font-family:'Font Awesome 6 Free';font-weight:900}.blockquote-center::after{border-bottom:1px solid #ccc;bottom:-20px;text-align:right;content:'\f10e';font-family:'Font Awesome 6 Free';font-weight:900}.blockquote-center div,.blockquote-center p{text-align:center}.group-picture{margin-bottom:20px}.group-picture .group-picture-row{display:flex;gap:3px;margin-bottom:3px}.group-picture .group-picture-column{flex:1}.group-picture .group-picture-column img{height:100%;margin:0;object-fit:cover;width:100%}.post-body .label{color:#555;padding:0 2px}.post-body .label.default{background:#f0f0f0}.post-body .label.primary{background:#efe6f7}.post-body .label.info{background:#e5f2f8}.post-body .label.success{background:#e7f4e9}.post-body .label.warning{background:#fcf6e1}.post-body .label.danger{background:#fae8eb}.post-body .link-grid{display:grid;grid-gap:1.5rem;gap:1.5rem;grid-template-columns:1fr 1fr;margin-bottom:20px;padding:1rem}.post-body .link-grid .link-grid-container{border:solid #ddd;box-shadow:1rem 1rem .5rem rgba(0,0,0,.5);min-height:5rem;min-width:0;padding:.5rem;position:relative;transition:background .3s}.post-body .link-grid .link-grid-container:hover{animation:.5s next-shake;background:var(--card-bg-color)}.post-body .link-grid .link-grid-container:active{box-shadow:.5rem .5rem .25rem rgba(0,0,0,.5);transform:translate(.2rem,.2rem)}.post-body .link-grid .link-grid-container .link-grid-image{border:1px solid #ddd;border-radius:50%;box-sizing:border-box;height:5rem;padding:3px;position:absolute;width:5rem}.post-body .link-grid .link-grid-container p{margin:0 1rem 0 6rem}.post-body .link-grid .link-grid-container p:first-of-type{font-size:1.2em}.post-body .link-grid .link-grid-container p:last-of-type{font-size:.8em;line-height:1.3rem;opacity:.7}.post-body .link-grid .link-grid-container a{border:0;height:100%;left:0;position:absolute;top:0;width:100%}@keyframes next-shake{0%{transform:translate(1pt,1pt) rotate(0)}10%{transform:translate(-1pt,-2pt) rotate(-1deg)}20%{transform:translate(-3pt,0) rotate(1deg)}30%{transform:translate(3pt,2pt) rotate(0)}40%{transform:translate(1pt,-1pt) rotate(1deg)}50%{transform:translate(-1pt,2pt) rotate(-1deg)}60%{transform:translate(-3pt,1pt) rotate(0)}70%{transform:translate(3pt,1pt) rotate(-1deg)}80%{transform:translate(-1pt,-1pt) rotate(1deg)}90%{transform:translate(1pt,2pt) rotate(0)}100%{transform:translate(1pt,-2pt) rotate(-1deg)}}.post-body .note{border-radius:3px;margin-bottom:20px;padding:1em;position:relative;border:1px solid #eee;border-left-width:5px}.post-body .note summary{cursor:pointer;outline:0}.post-body .note summary p{display:inline}.post-body .note h2,.post-body .note h3,.post-body .note h4,.post-body .note h5,.post-body .note h6{border-bottom:initial;margin:0;padding-top:0}.post-body .note :first-child{margin-top:0}.post-body .note :last-child{margin-bottom:0}.post-body .note.default{border-left-color:#777}.post-body .note.default h2,.post-body .note.default h3,.post-body .note.default h4,.post-body .note.default h5,.post-body .note.default h6{color:#777}.post-body .note.primary{border-left-color:#6f42c1}.post-body .note.primary h2,.post-body .note.primary h3,.post-body .note.primary h4,.post-body .note.primary h5,.post-body .note.primary h6{color:#6f42c1}.post-body .note.info{border-left-color:#428bca}.post-body .note.info h2,.post-body .note.info h3,.post-body .note.info h4,.post-body .note.info h5,.post-body .note.info h6{color:#428bca}.post-body .note.success{border-left-color:#5cb85c}.post-body .note.success h2,.post-body .note.success h3,.post-body .note.success h4,.post-body .note.success h5,.post-body .note.success h6{color:#5cb85c}.post-body .note.warning{border-left-color:#f0ad4e}.post-body .note.warning h2,.post-body .note.warning h3,.post-body .note.warning h4,.post-body .note.warning h5,.post-body .note.warning h6{color:#f0ad4e}.post-body .note.danger{border-left-color:#d9534f}.post-body .note.danger h2,.post-body .note.danger h3,.post-body .note.danger h4,.post-body .note.danger h5,.post-body .note.danger h6{color:#d9534f}.post-body .tabs{margin-bottom:20px}.post-body .tabs,.tabs-comment{padding-top:10px}.post-body .tabs ul.nav-tabs,.tabs-comment ul.nav-tabs{background:var(--content-bg-color);display:flex;display:flex;flex-wrap:wrap;justify-content:center;margin:0;padding:0;position:-webkit-sticky;position:sticky;top:0;z-index:5}.post-body .tabs ul.nav-tabs li.tab,.tabs-comment ul.nav-tabs li.tab{border-bottom:1px solid #ddd;border-left:1px solid transparent;border-right:1px solid transparent;border-radius:0;border-top:3px solid transparent;flex-grow:1;list-style-type:none}@media (max-width:413px){.post-body .tabs ul.nav-tabs,.tabs-comment ul.nav-tabs{display:block;margin-bottom:5px}.post-body .tabs ul.nav-tabs li.tab,.tabs-comment ul.nav-tabs li.tab{border-bottom:1px solid transparent;border-left:3px solid transparent;border-right:1px solid transparent;border-top:1px solid transparent;border-radius:0}}.post-body .tabs ul.nav-tabs li.tab a,.tabs-comment ul.nav-tabs li.tab a{border-bottom:initial;display:block;line-height:1.8;padding:.25em .75em;text-align:center;transition:.2s ease-out}.post-body .tabs ul.nav-tabs li.tab a i[class^=fa],.tabs-comment ul.nav-tabs li.tab a i[class^=fa]{width:1.285714285714286em}.post-body .tabs ul.nav-tabs li.tab.active,.tabs-comment ul.nav-tabs li.tab.active{border-color:#fc6423 #ddd transparent}@media (max-width:413px){.post-body .tabs ul.nav-tabs li.tab.active,.tabs-comment ul.nav-tabs li.tab.active{border-color:#ddd #ddd #ddd #fc6423}}.post-body .tabs ul.nav-tabs li.tab.active a,.tabs-comment ul.nav-tabs li.tab.active a{cursor:default}.post-body .tabs .tab-content,.tabs-comment .tab-content{border:1px solid #ddd;border-radius:0;border-top-color:transparent}@media (max-width:413px){.post-body .tabs .tab-content,.tabs-comment .tab-content{border-radius:0;border-top-color:#ddd}}.post-body .tabs .tab-content .tab-pane,.tabs-comment .tab-content .tab-pane{padding:20px 20px 0}.post-body .tabs .tab-content .tab-pane:not(.active),.tabs-comment .tab-content .tab-pane:not(.active){display:none}.pagination .next,.pagination .page-number,.pagination .prev,.pagination .space{display:inline-block;margin:-1px 10px 0;padding:0 10px}.algolia-pagination .current .page-number,.pagination .page-number.current{background:#ccc;border-color:#ccc;color:var(--content-bg-color)}.pagination{border-top:1px solid #eee;margin:120px 0 0;text-align:center}.pagination .next,.pagination .page-number,.pagination .prev{border-bottom:0;border-top:1px solid #eee;transition:border-color .2s ease-in-out}.pagination .next:hover,.pagination .page-number:hover,.pagination .prev:hover{border-top-color:var(--link-hover-color)}@media (max-width:767px){.post-body .link-grid{grid-template-columns:1fr}.pagination .next,.pagination .page-number,.pagination .prev,.pagination .space{margin:0 5px}.pagination{border-top:0}.pagination .next,.pagination .page-number,.pagination .prev{border-bottom:1px solid #eee;border-top:0}.pagination .next:hover,.pagination .page-number:hover,.pagination .prev:hover{border-bottom-color:var(--link-hover-color)}.site-meta{text-align:center}}.pagination .space{margin:0;padding:0}.comments{margin-top:60px;overflow:hidden}.comment-button-group{display:flex;display:flex;flex-wrap:wrap;justify-content:center;justify-content:center;margin:1em 0}.comment-button-group .comment-button{margin:.1em .2em}.comment-button-group .comment-button.active{background:var(--btn-default-hover-bg);border-color:var(--btn-default-hover-border-color);color:var(--btn-default-hover-color)}.comment-position{display:none}.comment-position.active{display:block}.tabs-comment{margin-top:4em;padding-top:0}.tabs-comment .comments{margin-top:0;padding-top:0}.headband{background:var(--theme-color);height:3px}@media (max-width:991px){.headband{display:none}}.site-brand-container{display:flex;flex-shrink:0;padding:0 10px}.use-motion .column,.use-motion .site-brand-container .toggle{opacity:0}.site-meta{flex-grow:1;text-align:center}.custom-logo-image{margin-top:20px}@media (max-width:991px){.custom-logo-image{display:none}}.brand{border-bottom:0;color:var(--brand-color);display:inline-block;padding:0}.brand:hover{color:var(--brand-hover-color)}.site-title{font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;font-size:1.375em;font-weight:400;line-height:1.5;margin:0}.site-subtitle{color:#ddd;font-size:.8125em;margin:10px 10px 0}.use-motion .custom-logo-image,.use-motion .site-subtitle,.use-motion .site-title{opacity:0;position:relative;top:-10px}.site-nav-right,.site-nav-toggle{display:none}.site-nav-right .toggle,.site-nav-toggle .toggle{color:var(--text-color);padding:10px;width:22px}.site-nav-right .toggle .toggle-line,.site-nav-toggle .toggle .toggle-line{background:var(--text-color);border-radius:1px}@media (max-width:767px){.site-nav-right,.site-nav-toggle{display:flex;flex-direction:column;justify-content:center}.site-nav{--scroll-height:0;height:0;overflow:hidden;transition:height .2s ease-in-out,visibility .2s ease-in-out;visibility:hidden}body:not(.site-nav-on) .site-nav .animated{animation:none}body.site-nav-on .site-nav{height:var(--scroll-height);visibility:unset}}.menu{margin:0;padding:1em 0;text-align:center}.menu-item{display:inline-block;list-style:none;margin:0 10px}@media (max-width:767px){.menu-item{display:block;margin-top:10px}.menu-item.menu-item-search{display:none}}.menu-item a{border-bottom:0;display:block;font-size:.8125em;transition:border-color .2s ease-in-out}.menu-item a.menu-item-active,.menu-item a:hover{background:var(--menu-item-bg-color)}.menu-item i[class^=fa]{margin-right:8px}.menu-item .badge{display:inline-block;font-weight:700;line-height:1;margin-left:.35em;margin-top:.35em;text-align:center;white-space:nowrap}.use-motion .menu-item{visibility:hidden}.github-corner :hover .octo-arm{animation:560ms ease-in-out octocat-wave}.github-corner svg{color:#fff;fill:var(--theme-color);position:absolute;right:0;top:0;z-index:5}@media (max-width:991px){.github-corner{display:none}.github-corner svg{color:var(--theme-color);fill:#fff}.github-corner .github-corner:hover .octo-arm{animation:none}.github-corner .github-corner .octo-arm{animation:560ms ease-in-out octocat-wave}}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}.sidebar-inner{color:#999;padding:18px 10px;text-align:center;display:flex;flex-direction:column;justify-content:center}.cc-license .cc-opacity{border-bottom:0;opacity:.7}.cc-license .cc-opacity:hover{opacity:.9}.cc-license img{display:inline-block}.site-author-image{border:1px solid #eee;max-width:120px;padding:2px}.site-author-name{color:var(--text-color);font-weight:600;margin:0}.site-description{color:#999;font-size:.8125em;margin-top:0}.links-of-author a{font-size:.8125em}.links-of-author i[class^=fa]{margin-right:2px}.sidebar .sidebar-button:not(:first-child){margin-top:15px}.sidebar .sidebar-button button{background:0 0;cursor:pointer;line-height:2;padding:0 15px;border-radius:4px}.sidebar .sidebar-button button i[class^=fa]{margin-right:5px}.links-of-blogroll{font-size:.8125em}.links-of-blogroll-title{font-size:.875em;font-weight:600}.links-of-blogroll-list{list-style:none;margin:0;padding:0}.sidebar-nav{font-size:.875em;height:0;margin:0;overflow:hidden;padding-left:0;pointer-events:none;transition:height .2s ease-in-out,visibility .2s ease-in-out;visibility:hidden}.sidebar-nav-active .sidebar-nav{height:calc(2em + 1px);pointer-events:unset;visibility:unset}.sidebar-nav li{border-bottom:1px solid transparent;color:var(--text-color);cursor:pointer;display:inline-block;transition:border-bottom-color .2s ease-in-out,color .2s ease-in-out}.sidebar-nav li.sidebar-nav-overview{margin-left:10px}.sidebar-nav li:hover{color:#fc6423}.sidebar-overview-active .sidebar-nav-overview,.sidebar-toc-active .sidebar-nav-toc{border-bottom-color:#fc6423;color:#fc6423;transition-delay:0.2s}.sidebar-overview-active .sidebar-nav-overview:hover,.sidebar-toc-active .sidebar-nav-toc:hover{color:#fc6423}.sidebar-panel-container{align-items:start;display:grid;flex:1;overflow-x:hidden;overflow-y:auto;padding-top:0;transition:padding-top .2s ease-in-out}.sidebar-nav-active .sidebar-panel-container{padding-top:20px}.sidebar-panel{animation:.2s ease-in-out deactivate-sidebar-panel;grid-area:1/1;height:0;opacity:0;overflow:hidden;pointer-events:none;transform:translateY(0);transition:.2s ease-in-out;transition-property:opacity,transform,visibility;visibility:hidden}.sidebar-nav-active .sidebar-panel,.sidebar-overview-active .sidebar-panel.post-toc-wrap{transform:translateY(-20px)}.sidebar-overview-active:not(.sidebar-nav-active) .sidebar-panel.post-toc-wrap{transition-delay:0s,0.2s,0s}.sidebar-overview-active .sidebar-panel.site-overview-wrap,.sidebar-toc-active .sidebar-panel.post-toc-wrap{animation-name:activate-sidebar-panel;height:auto;opacity:1;pointer-events:unset;transform:translateY(0);transition-delay:0.2s,0.2s,0s;visibility:unset}.sidebar-panel.site-overview-wrap{display:flex;flex-direction:column;justify-content:center;gap:10px;justify-content:flex-start}@keyframes deactivate-sidebar-panel{from{height:var(--inactive-panel-height,0)}to{height:var(--active-panel-height,0)}}@keyframes activate-sidebar-panel{from{height:var(--inactive-panel-height,auto)}to{height:var(--active-panel-height,auto)}}.sidebar-toggle{bottom:61px;height:16px;padding:5px;width:16px;background:#222;cursor:pointer;opacity:.6;position:fixed;z-index:30;right:30px}.sidebar-toggle:hover{opacity:.8}@media (max-width:991px){.sidebar-toggle{right:20px;opacity:.8}}.sidebar-toggle:hover .toggle-line{background:#fc6423}@media (any-hover:hover){body:not(.sidebar-active) .sidebar-toggle:hover :first-child{left:50%;top:2px;transform:rotate(45deg);width:50%}body:not(.sidebar-active) .sidebar-toggle:hover :last-child{left:50%;top:-2px;transform:rotate(-45deg);width:50%}}.sidebar-active .sidebar-toggle :nth-child(2){opacity:0}.sidebar-active .sidebar-toggle :first-child{top:6px;transform:rotate(45deg)}.sidebar-active .sidebar-toggle :last-child{top:-6px;transform:rotate(-45deg)}.post-toc{font-size:.875em}.post-toc ol{list-style:none;margin:0;padding:0 2px 0 10px;text-align:left}.post-toc ol>:last-child{margin-bottom:5px}.post-toc ol>ol{padding-left:0}.post-toc ol a{transition:.2s ease-in-out}.post-toc .nav-item{line-height:1.8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.post-toc .nav .nav-child{--height:0;height:0;opacity:0;overflow:hidden;transition:.2s ease-in-out;visibility:hidden}.post-toc .nav .active>.nav-child{height:var(--height,auto);opacity:1;visibility:unset}.post-toc .nav .active>a{border-bottom-color:#fc6423;color:#fc6423}.post-toc .nav .active-current>a,.post-toc .nav .active-current>a:hover{color:#fc6423}.site-state{display:flex;flex-wrap:wrap;justify-content:center;line-height:1.4}.site-state-item a{border-bottom:0;display:block}.site-state-item-count{display:block;font-size:1em;font-weight:600}.site-state-item-name{color:#999;font-size:.8125em}.sidebar-post-related{font-size:.8125em;padding:18px 0 0}.popular-posts{margin:0;padding:1em 0;text-align:left}.popular-posts .popular-posts-item{display:block}.popular-posts .popular-posts-item .popular-posts-link{border-bottom:0;display:block;padding:5px 20px;transition:background .2s ease-in-out}.popular-posts .popular-posts-item .popular-posts-link:hover{background:var(--menu-item-bg-color)}.popular-posts .popular-posts-item .popular-posts-time{color:#999}.footer{color:#999;font-size:.875em;padding:20px 0;transition:left .2s ease-in-out,right .2s ease-in-out}.footer.footer-fixed{bottom:0;left:0;position:absolute;right:0}.footer-inner{box-sizing:border-box;text-align:center;display:flex;flex-direction:column;justify-content:center;margin:0 auto;width:calc(100% - 20px)}@media (max-width:767px){.menu-item .badge{float:right;margin-left:0}.footer-inner{width:auto}}@media (min-width:1200px){.footer-inner{width:1160px}}@media (min-width:1600px){.footer-inner{width:73%}}.use-motion .footer{opacity:0}.languages{display:inline-block;font-size:1.125em;position:relative}.languages .lang-select-label span{margin:0 .5em}.languages .lang-select{height:100%;left:0;opacity:0;position:absolute;top:0;width:100%}.with-love{color:red;display:inline-block;margin:0 5px}.beian img{display:inline-block;margin:0 3px;vertical-align:middle}.busuanzi-count #busuanzi_container_site_pv,.busuanzi-count #busuanzi_container_site_uv{display:none}@keyframes icon-animate{0%,100%{transform:scale(1)}10%,30%{transform:scale(.9)}20%,40%,50%,60%,70%,80%{transform:scale(1.1)}}@media (max-width:567px){.main-inner{padding:initial!important}.posts-expand .post-header{margin-bottom:10px!important}.post-block{margin-top:initial!important;padding:8px 18px!important}.post-body h1,.post-body h2,.post-body h3,.post-body h4,.post-body h5,.post-body h6{margin:20px 0 8px}.post-body .note h1,.post-body .note h2,.post-body .note h3,.post-body .note h4,.post-body .note h5,.post-body .note h6,.post-body .tabs .tab-content .tab-pane h1,.post-body .tabs .tab-content .tab-pane h2,.post-body .tabs .tab-content .tab-pane h3,.post-body .tabs .tab-content .tab-pane h4,.post-body .tabs .tab-content .tab-pane h5,.post-body .tabs .tab-content .tab-pane h6{margin:0 5px}.post-body>p{margin:0 0 10px}.post-body .note>p,.post-body .tabs .tab-content .tab-pane>p{padding:0 5px}.post-body img,.post-body video{margin-bottom:10px!important}.post-body .fancybox+figcaption,.post-body img+figcaption{margin:-5px auto 15px!important}.post-body .note{margin-bottom:10px!important;padding:10px!important}.post-body .tabs .tab-content .tab-pane{padding:10px 10px 0!important}.post-eof{margin:40px auto 20px!important}.pagination{margin-top:40px}}.back-to-top{font-size:12px;align-items:center;bottom:-100px;color:#fff;display:flex;height:26px;transition:bottom .2s ease-in-out;background:#222;cursor:pointer;opacity:.6;position:fixed;z-index:30;right:30px}.back-to-top span{margin-right:8px;display:none}.back-to-top .fa{text-align:center;width:26px}.back-to-top:hover{opacity:.8;color:#fc6423}.back-to-top.back-to-top-on{bottom:30px}.rtl.post-body a,.rtl.post-body h1,.rtl.post-body h2,.rtl.post-body h3,.rtl.post-body h4,.rtl.post-body h5,.rtl.post-body h6,.rtl.post-body li,.rtl.post-body ol,.rtl.post-body p,.rtl.post-body ul{direction:rtl;font-family:UKIJ Ekran}.rtl.post-title{font-family:UKIJ Ekran}.post-button{margin-top:40px;text-align:center}.use-motion .collection-header,.use-motion .comments,.use-motion .pagination,.use-motion .post-block,.use-motion .post-body,.use-motion .post-header{visibility:hidden}.posts-collapse .post-content{margin-bottom:35px;margin-left:35px;position:relative}@media (max-width:767px){.posts-collapse .post-content{margin-left:0;margin-right:0}}.posts-collapse .post-content .collection-title{font-size:1.125em;position:relative}.posts-collapse .post-content .collection-title::before{background:#999;border:1px solid #fff;margin-left:-6px;margin-top:-4px;position:absolute;top:50%;border-radius:50%;content:' ';height:10px;width:10px}.posts-collapse .post-content .collection-year{font-size:1.5em;font-weight:700;margin:60px 0;position:relative}.posts-collapse .post-content .collection-year::before{background:#bbb;margin-left:-4px;margin-top:-4px;position:absolute;top:50%;border-radius:50%;content:' ';height:8px;width:8px}.posts-collapse .post-content .collection-header{display:block;margin-left:20px}.posts-collapse .post-content .collection-header small{color:#bbb;margin-left:5px}.posts-collapse .post-content .post-header{border-bottom:1px dashed #ccc;margin:30px 2px 0;padding-left:15px;position:relative;transition:border .2s ease-in-out}.posts-collapse .post-content .post-header::before{background:#bbb;border:1px solid #fff;left:-6px;position:absolute;top:.75em;transition:background .2s ease-in-out;border-radius:50%;content:' ';height:6px;width:6px}.posts-collapse .post-content .post-header:hover{border-bottom-color:#666}.posts-collapse .post-content .post-header:hover::before{background:#222}.posts-collapse .post-content .post-meta-container{display:inline;font-size:.75em;margin-right:10px}.posts-collapse .post-content .post-title{display:inline}.posts-collapse .post-content .post-title a{border-bottom:0;color:var(--link-color)}.posts-collapse .post-content::before{background:#f5f5f5;content:' ';height:100%;margin-left:-2px;position:absolute;top:1.25em;width:4px}.post-body{font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;overflow-wrap:break-word}@media (min-width:1200px){.post-body{font-size:1.125em}}@media (min-width:992px){.post-body{text-align:justify}}.post-body h1 .header-anchor,.post-body h1 .headerlink,.post-body h2 .header-anchor,.post-body h2 .headerlink,.post-body h3 .header-anchor,.post-body h3 .headerlink,.post-body h4 .header-anchor,.post-body h4 .headerlink,.post-body h5 .header-anchor,.post-body h5 .headerlink,.post-body h6 .header-anchor,.post-body h6 .headerlink{border-bottom-style:none;color:inherit;float:right;font-size:.875em;margin-left:10px;opacity:0}.post-body h1 .header-anchor::before,.post-body h1 .headerlink::before,.post-body h2 .header-anchor::before,.post-body h2 .headerlink::before,.post-body h3 .header-anchor::before,.post-body h3 .headerlink::before,.post-body h4 .header-anchor::before,.post-body h4 .headerlink::before,.post-body h5 .header-anchor::before,.post-body h5 .headerlink::before,.post-body h6 .header-anchor::before,.post-body h6 .headerlink::before{content:'\f0c1';font-family:'Font Awesome 6 Free';font-weight:900}.post-body h1:hover .header-anchor,.post-body h1:hover .headerlink,.post-body h2:hover .header-anchor,.post-body h2:hover .headerlink,.post-body h3:hover .header-anchor,.post-body h3:hover .headerlink,.post-body h4:hover .header-anchor,.post-body h4:hover .headerlink,.post-body h5:hover .header-anchor,.post-body h5:hover .headerlink,.post-body h6:hover .header-anchor,.post-body h6:hover .headerlink{opacity:.5}.post-body h1:hover .header-anchor:hover,.post-body h1:hover .headerlink:hover,.post-body h2:hover .header-anchor:hover,.post-body h2:hover .headerlink:hover,.post-body h3:hover .header-anchor:hover,.post-body h3:hover .headerlink:hover,.post-body h4:hover .header-anchor:hover,.post-body h4:hover .headerlink:hover,.post-body h5:hover .header-anchor:hover,.post-body h5:hover .headerlink:hover,.post-body h6:hover .header-anchor:hover,.post-body h6:hover .headerlink:hover{opacity:1}.post-body .exturl .fa{font-size:.875em;margin-left:4px}.post-body .fancybox+figcaption,.post-body img+figcaption{color:#999;font-size:.875em;font-weight:700;line-height:1;margin:-15px auto 15px;text-align:center}.post-body embed,.post-body iframe,.post-body img,.post-body video{margin-bottom:20px}.post-body .video-container{height:0;margin-bottom:20px;overflow:hidden;padding-top:75%;position:relative;width:100%}.post-body .video-container embed,.post-body .video-container iframe,.post-body .video-container object{height:100%;left:0;margin:0;position:absolute;top:0;width:100%}.post-gallery{display:flex;min-height:200px}.post-gallery .post-gallery-image{flex:1}.post-gallery .post-gallery-image:not(:first-child){clip-path:polygon(40px 0,100% 0,100% 100%,0 100%);margin-left:-20px}.post-gallery .post-gallery-image:not(:last-child){margin-right:-20px}.post-gallery .post-gallery-image img{height:100%;object-fit:cover;opacity:1;width:100%}.posts-expand .post-gallery{margin-bottom:60px}.posts-collapse .post-gallery{margin:15px 0}.posts-expand .post-header{font-size:1.125em;margin-bottom:60px;text-align:center}.posts-expand .post-title{font-size:1.5em;font-weight:400;margin:initial;overflow-wrap:break-word}.posts-expand .post-title-link{border-bottom:0;color:var(--link-color);display:inline-block;position:relative}.posts-expand .post-title-link::before{background:var(--link-color);bottom:0;content:'';height:2px;left:0;position:absolute;transform:scaleX(0);transition:transform .2s ease-in-out;width:100%}.posts-expand .post-title-link:hover::before{transform:scaleX(1)}.posts-expand .post-title-link .fa{font-size:.875em;margin-left:5px}.post-sticky-flag{display:inline-block;margin-right:8px;transform:rotate(30deg)}.posts-expand .post-meta-container{color:#999;font-family:Lato,'PingFang SC','Microsoft YaHei',sans-serif;font-size:.75em;margin-top:3px}.posts-expand .post-meta-container .post-description{font-size:.875em;margin-top:2px}.posts-expand .post-meta-container time{border-bottom:1px dashed #999}.post-meta{display:flex;flex-wrap:wrap;justify-content:center}:not(.post-meta-break)+.post-meta-item::before{content:'|';margin:0 .5em}.post-meta-item-icon{margin-right:3px}@media (max-width:991px){.back-to-top{right:20px;opacity:.8}.post-body{text-align:justify}.post-meta-item-text{display:none}}.post-meta-break{flex-basis:100%;height:0}#busuanzi_container_page_pv{display:none}.post-nav{border-top:1px solid #eee;display:flex;gap:30px;justify-content:space-between;margin-top:1em;padding:10px 5px 0}.post-nav-item{flex:1}.post-nav-item a{border-bottom:0;display:block;font-size:.875em;line-height:1.6}.post-nav-item a:active{top:2px}.post-nav-item .fa{font-size:.75em}.post-nav-item:first-child .fa{margin-right:5px}.post-nav-item:last-child{text-align:right}.post-nav-item:last-child .fa{margin-left:5px}.post-footer{display:flex;flex-direction:column;justify-content:center}.post-eof{background:#ccc;height:1px;margin:80px auto 60px;width:8%}.post-block:last-of-type .post-eof{display:none}.post-copyright ul{list-style:none;overflow:hidden;padding:.5em 1em;position:relative;background:var(--card-bg-color);border-left:3px solid #ff2a2a;margin:1em 0 0}.post-copyright ul::after{content:'\f25e';font-family:'Font Awesome 6 Brands';font-size:200px;opacity:.1;position:absolute;right:-50px;top:-150px}.post-tags{margin-top:40px;text-align:center}.post-tags a{display:inline-block;font-size:.8125em}.post-tags a:not(:last-child){margin-right:10px}.social-like{border-top:1px solid #eee;font-size:.875em;margin-top:1em;padding-top:1em;display:flex;flex-wrap:wrap;justify-content:center}.social-like a{border-bottom:none}.reward-container{margin:1em 0 0;padding:1em 0;text-align:center}.reward-container button{background:0 0;color:#fc6423;cursor:pointer;line-height:2;padding:0 15px;border:2px solid #fc6423;border-radius:2px;outline:0;transition:.2s ease-in-out;vertical-align:text-top}.reward-container button:hover{background:#fc6423;color:#fff}.post-reward{display:none;padding-top:20px}.post-reward.active{display:block}.post-reward div{display:inline-block}.post-reward div span{display:block}.post-reward img{display:inline-block;margin:.8em 2em 0;max-width:100%;width:180px}@keyframes next-roll{from{transform:rotateZ(30deg)}to{transform:rotateZ(-30deg)}}.category-all-page .category-all-title{text-align:center}.category-all-page .category-all{margin-top:20px}.category-all-page .category-list{list-style:none;margin:0;padding:0}.category-all-page .category-list-item{margin:5px 10px}.category-all-page .category-list-count{color:#bbb}.category-all-page .category-list-count::before{content:' ('}.category-all-page .category-list-count::after{content:') '}.category-all-page .category-list-child{padding-left:10px}.event-list hr{background:#222;margin:20px 0 45px}.event-list hr::after{background:#222;color:#fff;content:'NOW';display:inline-block;font-weight:700;padding:0 5px}.event-list .event{--event-background:#222;--event-foreground:#bbb;--event-title:#fff;background:var(--event-background);padding:15px}.event-list .event .event-summary{border-bottom:0;color:var(--event-title);margin:0;padding:0 0 0 35px;position:relative}.event-list .event .event-summary::before{animation:1s ease-in-out infinite alternate dot-flash;background:var(--event-title);left:0;margin-top:-6px;position:absolute;top:50%;border-radius:50%;content:' ';height:12px;width:12px}.event-list .event:nth-of-type(odd) .event-summary::before{animation-delay:.5s}.event-list .event:not(:last-child){margin-bottom:20px}.event-list .event .event-relative-time{color:var(--event-foreground);display:inline-block;font-size:12px;font-weight:400;padding-left:12px}.event-list .event .event-details{color:var(--event-foreground);display:block;line-height:18px;padding:6px 0 6px 35px}.event-list .event .event-details::before{color:var(--event-foreground);display:inline-block;margin-right:9px;width:14px;font-family:'Font Awesome 6 Free';font-weight:900}.event-list .event .event-details.event-location::before{content:'\f041'}.event-list .event .event-details.event-duration::before{content:'\f017'}.event-list .event .event-details.event-description::before{content:'\f024'}.event-list .event-past{--event-background:#f5f5f5;--event-foreground:#999;--event-title:#222}@keyframes dot-flash{from{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.8)}}ul.breadcrumb{font-size:.75em;list-style:none;margin:1em 0;padding:0 2em;text-align:center}ul.breadcrumb li{display:inline}ul.breadcrumb li:not(:first-child)::before{content:'/\00a0';font-weight:400;padding:.5em}ul.breadcrumb li:last-child{font-weight:700}.tag-cloud{text-align:center}.tag-cloud a{display:inline-block;margin:10px}.tag-cloud-0{border-bottom-color:#aaa;color:#aaa}.tag-cloud-1{border-bottom-color:#9a9a9a;color:#9a9a9a}.tag-cloud-2{border-bottom-color:#8b8b8b;color:#8b8b8b}.tag-cloud-3{border-bottom-color:#7c7c7c;color:#7c7c7c}.tag-cloud-4{border-bottom-color:#6c6c6c;color:#6c6c6c}.tag-cloud-5{border-bottom-color:#5d5d5d;color:#5d5d5d}.tag-cloud-6{border-bottom-color:#4e4e4e;color:#4e4e4e}.tag-cloud-7{border-bottom-color:#3e3e3e;color:#3e3e3e}.tag-cloud-8{border-bottom-color:#2f2f2f;color:#2f2f2f}.tag-cloud-9{border-bottom-color:#202020;color:#202020}.tag-cloud-10{border-bottom-color:#111;color:#111}.search-active{overflow:hidden}.search-pop-overlay{background:rgba(0,0,0,0);display:flex;height:100%;left:0;position:fixed;top:0;transition:visibility .4s,background .4s;visibility:hidden;width:100%;z-index:40}.search-active .search-pop-overlay{background:rgba(0,0,0,.3);visibility:visible}.search-popup{background:var(--card-bg-color);border-radius:5px;height:80%;margin:auto;transform:scale(0);transition:transform .4s;width:700px}.search-active .search-popup{transform:scale(1)}@media (max-width:767px){.search-popup{border-radius:0;height:100%;width:100%}}.search-popup .popup-btn-close,.search-popup .search-icon{color:#999;font-size:18px;padding:0 10px}.search-popup .popup-btn-close{cursor:pointer}.search-popup .popup-btn-close:hover .fa{color:#222}.search-popup .search-header{background:#eee;border-top-left-radius:5px;border-top-right-radius:5px;display:flex;padding:5px}.search-popup input.search-input{background:0 0;border:0;outline:0;width:100%}.search-popup input.search-input::-webkit-search-cancel-button{display:none}.search-popup .search-result-container{height:calc(100% - 55px);overflow:auto;padding:5px 25px}.search-popup .search-result-container hr{margin:5px 0 10px}.search-popup .search-result-container hr:first-child{display:none}.search-popup .search-result-list{margin:0 5px;padding:0}.search-popup a.search-result-title{font-weight:700}.search-popup p.search-result{border-bottom:1px dashed #ccc;padding:5px 0}.search-input-container{flex-grow:1}.search-input-container form{padding:2px}.search-stats{align-items:center;display:flex;justify-content:space-between}.search-stats img{height:1em;margin:0}.algolia-pagination{margin:40px 0;opacity:1;padding:0}.algolia-pagination .pagination-item{display:inline-block}.algolia-pagination .current .page-number{cursor:default}.algolia-pagination .disabled-item{visibility:hidden}.use-motion .animated{animation-fill-mode:none;visibility:inherit}.use-motion .sidebar .animated{animation-fill-mode:both}header.header{background:var(--content-bg-color);border-radius:initial;box-shadow:initial}.main{align-items:stretch;display:flex;justify-content:space-between;margin:0 auto;width:calc(100% - 20px)}@media (max-width:767px){.main{width:auto}}@media (min-width:1200px){.main{width:1160px}}@media (min-width:1600px){.main{width:73%}}@media (max-width:991px){header.header{border-radius:initial}.main{display:block;width:auto}}.main-inner{border-radius:initial;box-sizing:border-box;width:calc(100% - 252px)}.footer-inner{padding-left:252px}@media (max-width:991px){.main-inner{border-radius:initial;width:100%}.footer-inner{padding-left:0;padding-right:0;width:auto}}.column{width:240px}.site-brand-container{background:var(--theme-color)}.site-meta{padding:20px 0}.site-nav-right .toggle,.site-nav-toggle .toggle{color:#fff}.site-nav-right .toggle .toggle-line,.site-nav-toggle .toggle .toggle-line{background:#fff}@media (min-width:768px) and (max-width:991px){.site-nav-right,.site-nav-toggle{display:flex;flex-direction:column;justify-content:center}.site-nav{--scroll-height:0;height:0;overflow:hidden;transition:height .2s ease-in-out,visibility .2s ease-in-out;visibility:hidden}body:not(.site-nav-on) .site-nav .animated{animation:none}body.site-nav-on .site-nav{height:var(--scroll-height);visibility:unset}}.menu .menu-item{display:block;margin:0}.menu .menu-item a{padding:5px 20px;position:relative;text-align:left;transition-property:background-color}.menu .menu-item .badge{background:#ccc;border-radius:10px;color:var(--content-bg-color);float:right;padding:2px 5px;text-shadow:1px 1px 0 rgba(0,0,0,.1)}.main-menu .menu-item-active::after{background:#bbb;border-radius:50%;content:' ';height:6px;margin-top:-3px;position:absolute;right:15px;top:50%;width:6px}.sub-menu{margin:0;padding:6px 0}.sub-menu .menu-item{display:inline-block}.sub-menu .menu-item a{background:0 0;margin:5px 10px;padding:initial}.sub-menu .menu-item a:hover{background:0 0;color:#fc6423}.sub-menu .menu-item-active{border-bottom-color:#fc6423;color:#fc6423}.sub-menu .menu-item-active:hover{border-bottom-color:#fc6423}.sidebar{position:-webkit-sticky;position:sticky;top:12px}@media (max-width:991px){.column{width:auto}.site-nav-on .site-brand-container{box-shadow:0 0 16px rgba(0,0,0,.5)}.menu .menu-item.menu-item-search,.sidebar{display:none}}.sidebar-inner{background:var(--content-bg-color);border-radius:initial;box-shadow:initial;box-sizing:border-box;color:var(--text-color);margin-top:12px;max-height:calc(100vh - 24px);visibility:hidden}.site-state-item{padding:0 10px}.sidebar .sidebar-button{border-bottom:1px dotted #ccc;border-top:1px dotted #ccc}.sidebar .sidebar-button button{border:0;color:#fc6423;display:block;width:100%}.sidebar .sidebar-button button:hover{background:0 0;border:0;color:#e34603}.links-of-author{display:flex;flex-wrap:wrap;justify-content:center}.links-of-author-item{margin:5px 0 0;width:50%}.links-of-author-item a{box-sizing:border-box;max-width:100%;overflow:hidden;padding:0 5px;text-overflow:ellipsis;white-space:nowrap;border-bottom:0;border-radius:4px;display:block}.links-of-author-item a:hover{background:var(--body-bg-color)}.main-inner{background:var(--content-bg-color);box-shadow:initial;padding:40px}@media (max-width:991px){.main-inner{padding:20px}}.sub-menu{border-bottom:1px solid #ddd}.post-block:first-of-type{padding-top:40px}@media (max-width:767px){.pagination{margin-bottom:10px}}</style><link as=style href=https://fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&display=swap&subset=latin,latin-ext onload=this.rel='stylesheet' rel=preload><link crossorigin=anonymous href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css integrity=sha256-yIDrPSXHZdOZhAqiBP7CKzIwMQmRCJ8UeB8Jo17YC4o= rel=stylesheet><link crossorigin=anonymous href=https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.1.1/animate.min.css integrity=sha256-PR7ttpcvz8qrF57fur/yAx1qXMFJeJFiA6pSzWi0OIE= rel=stylesheet><link crossorigin=anonymous href=https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.css integrity=sha256-6cQIC71/iBIYXFK+0RHAvwmjwWzkWd+r7v/BX3/vZDc= rel=stylesheet><script class=next-config data-name=main type=application/json>{"hostname":"nicksxs.me","root":"/","images":"/images","scheme":"Pisces","darkmode":false,"version":"8.19.1","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12},"copycode":{"enable":true,"style":"default"},"fold":{"enable":false,"height":500},"bookmark":{"enable":false,"color":"#222","save":"auto"},"mediumzoom":false,"lazyload":true,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"stickytabs":false,"motion":{"enable":true,"async":false,"transition":{"menu_item":"fadeInDown","post_block":"fadeIn","post_header":"fadeInDown","post_body":"fadeInDown","coll_header":"fadeInLeft","sidebar":"fadeInUp"}},"prism":false,"i18n":{"placeholder":"搜索...","empty":"没有找到任何搜索结果:${query}","hits_time":"找到 ${hits} 个搜索结果(用时 ${time} 毫秒)","hits":"找到 ${hits} 个搜索结果"},"algolia":{"appID":"663Q99OQQD","apiKey":"e461a1371d12cec1491c1153b288a9ed","indexName":"nicksxs","hits":{"per_page":10}}}</script><script src=/js/config.js></script><meta content="learn from zero,技术博客,Nicksxs,史学森" name=description><meta content=website property=og:type><meta content="Nicksxs's Blog" property=og:title><meta content=https://nicksxs.me/index.html property=og:url><meta content="Nicksxs's Blog" property=og:site_name><meta content="learn from zero,技术博客,Nicksxs,史学森" property=og:description><meta content=zh_CN property=og:locale><meta content=Nicksxs property=article:author><meta content=Nicksxs,史学森,米方方,米方方的男朋友,森哥 property=article:tag><meta content=summary name=twitter:card><link href=https://nicksxs.me/ rel=canonical><script class=next-config data-name=page type=application/json>{"sidebar":"","isHome":true,"isPost":false,"lang":"zh-CN","comments":"","permalink":"","path":"index.html","title":""}</script><script class=next-config data-name=calendar type=application/json>""</script><title>Nicksxs's Blog - What hurts more, the pain of hard work or the pain of regret?</title><script async src=https://www.googletagmanager.com/gtag/js?id=UA-61358619-1></script><script class=next-config data-name=google_analytics type=application/json>{"tracking_id":"UA-61358619-1","only_pageview":false,"measure_protocol_api_secret":null}</script><script src=/js/third-party/analytics/google-analytics.js></script><script src=/js/third-party/analytics/baidu-analytics.js></script><script async src=https://hm.baidu.com/hm.js?20f33b3c0c0eff9b1522999c0015646d></script><noscript><link href=/css/noscript.css rel=stylesheet></noscript><link title="Nicksxs's Blog" href=/atom.xml rel=alternate type=application/atom+xml><body class=use-motion itemscope itemtype=http://schema.org/WebPage><div class=headband></div><main class=main><div class=column><header class=header itemscope itemtype=http://schema.org/WPHeader><div class=site-brand-container><div class=site-nav-toggle><div aria-label=切换导航栏 class=toggle role=button><span class=toggle-line></span><span class=toggle-line></span><span class=toggle-line></span></div></div><div class=site-meta><a class=brand href=/ rel=start><i class=logo-line></i><h1 class=site-title>Nicksxs's Blog</h1><i class=logo-line></i></a><p class=site-subtitle itemprop=description>What hurts more, the pain of hard work or the pain of regret?</div><div class=site-nav-right><div class="toggle popup-trigger" aria-label=搜索 role=button><i class="fa fa-search fa-fw fa-lg"></i></div></div></div><nav class=site-nav><ul class="main-menu menu"><li class="menu-item menu-item-home"><a href=/ rel=section><i class="fa fa-home fa-fw"></i>首页</a><li class="menu-item menu-item-about"><a href=/about/ rel=section><i class="fa fa-user fa-fw"></i>关于我</a><li class="menu-item menu-item-mirror"><a href=https://nicksxs.com/ rel=section target=_blank><i class="fa fa-user fa-fw"></i>国内镜像</a><li class="menu-item menu-item-tags"><a href=/tags/ rel=section><i class="fa fa-tags fa-fw"></i>标签</a><li class="menu-item menu-item-categories"><a href=/categories/ rel=section><i class="fa fa-th fa-fw"></i>分类</a><li class="menu-item menu-item-archives"><a href=/archives/ rel=section><i class="fa fa-archive fa-fw"></i>归档</a><li class="menu-item menu-item-top"><a href=/top/ rel=section><i class="fa fa-th fa-fw"></i>热度</a><li class="menu-item menu-item-sitemap"><a href=/sitemap.xml rel=section><i class="fa fa-sitemap fa-fw"></i>站点地图</a><li class="menu-item menu-item-commonweal"><a href=/404/ rel=section><i class="fa fa-heartbeat fa-fw"></i>公益 404</a><li class="menu-item menu-item-search"><a class=popup-trigger role=button><i class="fa fa-search fa-fw"></i>搜索</a></ul></nav><div class=search-pop-overlay><div class="popup search-popup"><div class=search-header><span class=search-icon><i class="fa fa-search"></i></span><div class=search-input-container></div><span class=popup-btn-close role=button><i class="fa fa-times-circle"></i></span></div><div class=search-result-container><div class=algolia-stats><hr></div><div class=algolia-hits></div><div class=algolia-pagination></div></div></div></div></header><aside class=sidebar><div class="sidebar-inner sidebar-overview-active"><ul class=sidebar-nav><li class=sidebar-nav-toc>文章目录<li class=sidebar-nav-overview>站点概览</ul><div class=sidebar-panel-container><div class="post-toc-wrap sidebar-panel"></div><div class="site-overview-wrap sidebar-panel"><div class="site-author animated" itemprop=author itemscope itemtype=http://schema.org/Person><img alt=Nicksxs class=site-author-image itemprop=image src=/uploads/avatar.jpg><p class=site-author-name itemprop=name>Nicksxs<div class=site-description itemprop=description>learn from zero,技术博客,Nicksxs,史学森</div></div><div class="site-state-wrap animated"><nav class=site-state><div class="site-state-item site-state-posts"><a href=/archives/><span class=site-state-item-count>384</span> <span class=site-state-item-name>日志</span></a></div><div class="site-state-item site-state-categories"><a href=/categories/><span class=site-state-item-count>181</span> <span class=site-state-item-name>分类</span></a></div><div class="site-state-item site-state-tags"><a href=/tags/><span class=site-state-item-count>321</span> <span class=site-state-item-name>标签</span></a></div></nav></div><div class="links-of-author animated"><span class=links-of-author-item><a rel="noopener me" title="GitHub → https://github.com/nicksxs" href=https://github.com/nicksxs target=_blank><i class="fab fa-github fa-fw"></i>GitHub</a> </span><span class=links-of-author-item><a rel="noopener me" title="E-Mail → mailto:nicksxs1202@gmail.com" href=mailto:nicksxs1202@gmail.com target=_blank><i class="fa fa-envelope fa-fw"></i>E-Mail</a></span></div><div class="cc-license animated" itemprop=license><a class=cc-opacity href=https://creativecommons.org/licenses/by-nc-sa/4.0/ rel=noopener target=_blank><img alt="Creative Commons" src=https://cdnjs.cloudflare.com/ajax/libs/creativecommons-vocabulary/2020.11.3/assets/license_badges/small/by_nc_sa.svg></a></div><div class=post-gallery itemscope itemtype=http://schema.org/ImageGallery style=height:120px;min-height:120px><div class=post-gallery-row><a class="post-gallery-img fancybox" href=https://url.cn/LLWrL7gx itemprop=url itemscope itemtype=http://schema.org/ImageObject rel=gallery_ target=_blank><img alt=腾讯云推广 itemprop=contentUrl src=https://img.nicksxs.com/blog/345X200.jpg style=padding:12px></a></div></div><div data-text-font="Trebuchet MS, Helvetica" class=widget-wrap data-canvas-id=sidebar-tag-cloud-canvas data-freeze-active=true data-max-speed=0.1 data-outline-colour=#E2E1D1 data-script-src=/js/tagcanvas.js data-tag-cloud data-text-colour=#333 data-text-height=20><div class="widget tagcloud" data-tag-cloud-container id=myCanvasContainer><canvas height=250 id=sidebar-tag-cloud-canvas style=width:100% width=250><ul class=tag-list itemprop=keywords><li class=tag-list-item><a class=tag-list-link href=/tags/Java/ rel=tag>Java</a><li class=tag-list-item><a class=tag-list-link href=/tags/java/ rel=tag>java</a><li class=tag-list-item><a class=tag-list-link href=/tags/leetcode/ rel=tag>leetcode</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%94%9F%E6%B4%BB/ rel=tag>生活</a><li class=tag-list-item><a class=tag-list-link href=/tags/LLM/ rel=tag>LLM</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E9%A2%98%E8%A7%A3/ rel=tag>题解</a><li class=tag-list-item><a class=tag-list-link href=/tags/SpringBoot/ rel=tag>SpringBoot</a><li class=tag-list-item><a class=tag-list-link href=/tags/c/ rel=tag>c++</a><li class=tag-list-item><a class=tag-list-link href=/tags/Tomcat/ rel=tag>Tomcat</a><li class=tag-list-item><a class=tag-list-link href=/tags/Mysql/ rel=tag>Mysql</a><li class=tag-list-item><a class=tag-list-link href=/tags/Mybatis/ rel=tag>Mybatis</a><li class=tag-list-item><a class=tag-list-link href=/tags/redis/ rel=tag>redis</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B0%8F%E6%8A%80%E5%B7%A7/ rel=tag>小技巧</a><li class=tag-list-item><a class=tag-list-link href=/tags/mysql/ rel=tag>mysql</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/ rel=tag>数据结构</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%BA%90%E7%A0%81/ rel=tag>源码</a><li class=tag-list-item><a class=tag-list-link href=/tags/MQ/ rel=tag>MQ</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/ rel=tag>消息队列</a><li class=tag-list-item><a class=tag-list-link href=/tags/RocketMQ/ rel=tag>RocketMQ</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%BF%90%E5%8A%A8/ rel=tag>运动</a><li class=tag-list-item><a class=tag-list-link href=/tags/php/ rel=tag>php</a><li class=tag-list-item><a class=tag-list-link href=/tags/Spring/ rel=tag>Spring</a><li class=tag-list-item><a class=tag-list-link href=/tags/linux/ rel=tag>linux</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%87%8F%E8%82%A5/ rel=tag>减肥</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%B7%91%E6%AD%A5/ rel=tag>跑步</a><li class=tag-list-item><a class=tag-list-link href=/tags/Dubbo/ rel=tag>Dubbo</a><li class=tag-list-item><a class=tag-list-link href=/tags/headscale/ rel=tag>headscale</a><li class=tag-list-item><a class=tag-list-link href=/tags/Windows/ rel=tag>Windows</a><li class=tag-list-item><a class=tag-list-link href=/tags/Docker/ rel=tag>Docker</a><li class=tag-list-item><a class=tag-list-link href=/tags/git/ rel=tag>git</a><li class=tag-list-item><a class=tag-list-link href=/tags/nas/ rel=tag>nas</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B9%B2%E6%B4%BB/ rel=tag>干活</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%AE%97%E6%B3%95/ rel=tag>算法</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B7%A5%E5%85%B7/ rel=tag>工具</a><li class=tag-list-item><a class=tag-list-link href=/tags/llm/ rel=tag>llm</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%B3%9F%E5%BF%83%E4%BA%8B/ rel=tag>糟心事</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ rel=tag>年终总结</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%AF%BB%E5%90%8E%E6%84%9F/ rel=tag>读后感</a><li class=tag-list-item><a class=tag-list-link href=/tags/Apollo/ rel=tag>Apollo</a><li class=tag-list-item><a class=tag-list-link href=/tags/RPC/ rel=tag>RPC</a><li class=tag-list-item><a class=tag-list-link href=/tags/nginx/ rel=tag>nginx</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%89%8A%E5%B3%B0%E5%A1%AB%E8%B0%B7/ rel=tag>削峰填谷</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%B8%AD%E9%97%B4%E4%BB%B6/ rel=tag>中间件</a><li class=tag-list-item><a class=tag-list-link href=/tags/markdown/ rel=tag>markdown</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E8%A7%84%E5%88%99/ rel=tag>规则</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%9D%AD%E5%B7%9E/ rel=tag>杭州</a><li class=tag-list-item><a class=tag-list-link href=/tags/2021/ rel=tag>2021</a><li class=tag-list-item><a class=tag-list-link href=/tags/aqs/ rel=tag>aqs</a><li class=tag-list-item><a class=tag-list-link href=/tags/C/ rel=tag>C++</a><li class=tag-list-item><a class=tag-list-link href=/tags/Disruptor/ rel=tag>Disruptor</a><li class=tag-list-item><a class=tag-list-link href=/tags/Binary-Tree/ rel=tag>Binary Tree</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E4%BA%8C%E5%8F%89%E6%A0%91/ rel=tag>二叉树</a><li class=tag-list-item><a class=tag-list-link href=/tags/grep/ rel=tag>grep</a><li class=tag-list-item><a class=tag-list-link href=/tags/namespace/ rel=tag>namespace</a><li class=tag-list-item><a class=tag-list-link href=/tags/ssh/ rel=tag>ssh</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E7%AB%AF%E5%8F%A3%E8%BD%AC%E5%8F%91/ rel=tag>端口转发</a><li class=tag-list-item><a class=tag-list-link href=/tags/Rust/ rel=tag>Rust</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%89%80%E6%9C%89%E6%9D%83/ rel=tag>所有权</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E5%86%85%E5%AD%98%E5%88%86%E5%B8%83/ rel=tag>内存分布</a><li class=tag-list-item><a class=tag-list-link href=/tags/%E6%96%B0%E8%AF%AD%E8%A8%80/ rel=tag>新语言</a></ul></canvas></div></div><script defer src=/js/tagcloud-loader.js></script></div></div></div><div class="sidebar-inner sidebar-blogroll"><div class="links-of-blogroll animated"><div class=links-of-blogroll-title><i class="fa fa-globe fa-fw"></i> 链接</div><ul class=links-of-blogroll-list><li class=links-of-blogroll-item><a href=https://covermusic.cn/ rel=noopener target=_blank title=https://covermusic.cn>69伙伴</a></ul></div></div></aside></div><div class="main-inner index posts-expand"><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2026/08/16/%E8%AE%A9chatgpt%E6%9D%A5%E7%BB%99%E6%88%91%E8%AE%B2%E8%A7%A3%E4%B8%8Bdeepseek-harness%E7%9A%84%E6%8F%92%E4%BB%B6%E4%BD%93%E7%B3%BB/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2026/08/16/%E8%AE%A9chatgpt%E6%9D%A5%E7%BB%99%E6%88%91%E8%AE%B2%E8%A7%A3%E4%B8%8Bdeepseek-harness%E7%9A%84%E6%8F%92%E4%BB%B6%E4%BD%93%E7%B3%BB/ itemprop=url>让chatgpt来给我讲解下deepseek harness的插件体系</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2026-08-16 23:07:34 / 修改时间:23:08:30" datetime=2026-08-16T23:07:34+08:00>2026-08-16</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/LLM/ itemprop=url rel=index><span itemprop=name>LLM</span></a> </span></span><span class="post-meta-item cloudflare-page-counter" data-title="让chatgpt来给我讲解下deepseek harness的插件体系" data-increment=false data-path=/2026/08/16/%E8%AE%A9chatgpt%E6%9D%A5%E7%BB%99%E6%88%91%E8%AE%B2%E8%A7%A3%E4%B8%8Bdeepseek-harness%E7%9A%84%E6%8F%92%E4%BB%B6%E4%BD%93%E7%B3%BB/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=cloudflare-page-counter-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2026/08/16/%E8%AE%A9chatgpt%E6%9D%A5%E7%BB%99%E6%88%91%E8%AE%B2%E8%A7%A3%E4%B8%8Bdeepseek-harness%E7%9A%84%E6%8F%92%E4%BB%B6%E4%BD%93%E7%B3%BB/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2026/08/16/让chatgpt来给我讲解下deepseek-harness的插件体系/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>最近deepseek发布了harness,试用了一下结合deepseek-4-flash,用它尝试写一个php的现代版phpmyadmin,因为也是一个比较重要且有一点复杂度的应用<br>试了下除了数据展示有点问题,修了一轮就完成了,整体表现还是不错的<br>然后看了下它主打的是万物都是插件<br>这个概念还是比较复杂的,尝试让gpt老师帮我讲解下<br>DeepSeek Harness 就像一个“由很多小员工临时组成的公司”。<br>没有一个超级总经理包办所有事情:<ul><li>一个员工负责问大模型;<li>一个员工负责读文件;<li>一个员工负责运行命令;<li>一个员工负责审批危险操作;<li>一个员工负责保存聊天记录;<li>一个员工负责显示网页界面。<br>这些“员工”就是插件。<br>需要什么员工,就把什么员工叫来;不需要了,就让它离开,并自动收拾自己留下的东西。</ul><h2 id=用一个真实请求走一遍><a class=headerlink href=#用一个真实请求走一遍 title=用一个真实请求走一遍></a>用一个真实请求走一遍</h2><p>你对 DeepSeek Harness 说:<blockquote><p>帮我读取 package.json,看看项目用了哪些依赖。<br>系统内部大致发生了这些事:</blockquote><figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br><span class=line>14</span><br><span class=line>15</span><br><span class=line>16</span><br><span class=line>17</span><br><span class=line>18</span><br><span class=line>19</span><br></pre><td class=code><pre><span class=line>你输入问题</span><br><span class=line> ↓</span><br><span class=line>Agent Loop 插件:决定下一步做什么</span><br><span class=line> ↓</span><br><span class=line>LLM 插件:把问题发给 DeepSeek</span><br><span class=line> ↓</span><br><span class=line>DeepSeek 返回:我要调用 read_file</span><br><span class=line> ↓</span><br><span class=line>权限插件:这个文件允许读吗?</span><br><span class=line> ↓</span><br><span class=line>文件工具插件:读取 package.json</span><br><span class=line> ↓</span><br><span class=line>日志插件:记录本次工具调用</span><br><span class=line> ↓</span><br><span class=line>Agent Loop 插件:把文件内容再次交给 DeepSeek</span><br><span class=line> ↓</span><br><span class=line>DeepSeek 生成最终回答</span><br><span class=line> ↓</span><br><span class=line>Web UI 插件:把回答显示出来</span><br></pre></table></figure><p>关键点是:<br>上面每一个步骤都可以由不同插件负责。<br>比如你可以:<ul><li>把 DeepSeek 换成其他模型;<li>把本地文件系统换成远程沙箱;<li>给文件读取前增加权限检查;<li>给模型调用增加重试;<li>给工具调用增加日志;<li>换掉整个 Agent Loop。<br>其他部分不需要跟着重写。</ul><h2 id=为什么普通插件系统做不到这么灵活><a class=headerlink href=#为什么普通插件系统做不到这么灵活 title=为什么普通插件系统做不到这么灵活></a>为什么普通插件系统做不到这么灵活</h2><p>普通软件的结构经常是:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br></pre><td class=code><pre><span class=line>固定核心程序</span><br><span class=line>├── 插件位置 A</span><br><span class=line>├── 插件位置 B</span><br><span class=line>└── 插件位置 C</span><br></pre></table></figure><p>核心程序是老板,插件只能填几个预留位置。<br>DeepSeek Harness 更像:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br></pre><td class=code><pre><span class=line>极小的组装平台</span><br><span class=line>├── Agent Loop 插件</span><br><span class=line>├── 模型插件</span><br><span class=line>├── 工具插件</span><br><span class=line>├── 权限插件</span><br><span class=line>├── 存储插件</span><br><span class=line>└── UI 插件</span><br></pre></table></figure><p>连“核心 Agent 怎么循环运行”本身也是插件。<br>所以它不是:<blockquote><p>一个 Agent,加上一些插件。<br>而是:<br>很多插件组合起来以后,才形成一个 Agent。</blockquote><h2 id=插件之间怎么找到对方><a class=headerlink href=#插件之间怎么找到对方 title=插件之间怎么找到对方></a>插件之间怎么找到对方</h2><p>假设你写了一个天气工具插件。<br>它不能一启动就直接工作,因为它要先找到“工具管理器”。<br>所以它会声明:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line>我需要:tools 服务</span><br></pre></table></figure><p>代码里大概是:<figure class="highlight ts"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line><span class=keyword>export</span> <span class=keyword>const</span> inject = [<span class=string>'tools'</span>]</span><br></pre></table></figure><p>意思就是:<blockquote><p>只有工具管理器存在时,才启动我。<br>系统启动时可能出现这种情况:</blockquote><figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br></pre><td class=code><pre><span class=line>天气插件:我需要 tools</span><br><span class=line>工具管理器:还没启动</span><br><span class=line>天气插件:那我先等着</span><br><span class=line></span><br><span class=line>工具管理器启动</span><br><span class=line>天气插件:条件满足,现在开始工作</span><br></pre></table></figure><p>如果工具管理器后来被替换:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br></pre><td class=code><pre><span class=line>旧工具管理器卸载</span><br><span class=line> ↓</span><br><span class=line>天气插件也暂时卸载</span><br><span class=line> ↓</span><br><span class=line>新工具管理器启动</span><br><span class=line> ↓</span><br><span class=line>天气插件重新启动,并连接新管理器</span><br></pre></table></figure><p>这就是 DeepSeek Harness 很特别的地方:<blockquote><p>插件依赖不是只在启动时检查一次,而是一直被系统关注。</blockquote><h2 id=ctx-到底是什么><a title="ctx 到底是什么" class=headerlink href=#ctx-到底是什么></a><code>ctx</code> 到底是什么</h2><p>插件启动时会拿到一个 <code>ctx</code>:<figure class="highlight ts"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line><span class=keyword>export</span> <span class=keyword>function</span> <span class="title function_">apply</span>(<span class=params>ctx</span>) {</span><br><span class=line> <span class=comment>// 使用 ctx 做事</span></span><br><span class=line>}</span><br></pre></table></figure><p>你可以把 <code>ctx</code> 理解成“公司总机”。<br>插件不知道其他插件住在哪里,只需要问总机:<figure class="highlight ts"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>ctx.<span class=property>tools</span> <span class=comment>// 工具管理器</span></span><br><span class=line>ctx.<span class=property>llm</span> <span class=comment>// 模型管理器</span></span><br><span class=line>ctx.<span class=property>sessions</span> <span class=comment>// 会话管理器</span></span><br><span class=line>ctx.<span class=property>fs</span> <span class=comment>// 文件系统</span></span><br><span class=line>ctx.<span class=property>sandbox</span> <span class=comment>// 沙箱</span></span><br></pre></table></figure><p>比如天气插件说:<figure class="highlight ts"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line>ctx.<span class=property>tools</span>.<span class="title function_">register</span>(weatherTool)</span><br></pre></table></figure><p>意思就是:<blockquote><p>总机,请把我的天气能力登记到工具管理器里。<br>这样天气插件不需要自己找到 Agent Loop,也不需要直接修改模型提示词。工具管理器会负责把天气工具告诉模型。</blockquote><h2 id=插件卸载时,怎么避免留下垃圾><a class=headerlink href=#插件卸载时,怎么避免留下垃圾 title=插件卸载时,怎么避免留下垃圾></a>插件卸载时,怎么避免留下垃圾</h2><p>这是整个系统最值得理解的设计。<br>假设天气插件启动后做了三件事:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line>1. 注册 weather 工具</span><br><span class=line>2. 监听工具调用事件</span><br><span class=line>3. 启动一个定时器</span><br></pre></table></figure><p>如果只是粗暴地删除插件代码,可能留下:<ul><li>一个无法调用的 weather 工具;<li>一个永远存在的事件监听器;<li>一个一直运行的定时器。<br>DeepSeek Harness 要求插件在创建东西时,同时登记“怎么撤销”。<br>可以理解成:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br></pre><td class=code><pre><span class=line>创建 weather 工具</span><br><span class=line>同时记下:卸载时删除 weather 工具</span><br><span class=line></span><br><span class=line>添加事件监听器</span><br><span class=line>同时记下:卸载时移除监听器</span><br><span class=line></span><br><span class=line>启动定时器</span><br><span class=line>同时记下:卸载时停止定时器</span><br></pre></table></figure>于是卸载插件时,系统会自动倒着清理:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line>停止定时器</span><br><span class=line>移除监听器</span><br><span class=line>删除 weather 工具</span><br></pre></table></figure>所以热更新才比较可靠。<br>修改天气插件代码后,系统可以:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>完整清理旧天气插件</span><br><span class=line> ↓</span><br><span class=line>重新加载新代码</span><br><span class=line> ↓</span><br><span class=line>重新注册新天气工具</span><br></pre></table></figure>而不是让新旧两套东西同时残留。<br>这个“创建时顺便记录撤销方法”的机制,技术上叫 <code>effect</code>。</ul><h2 id=Fiber-又是什么><a title="Fiber 又是什么" class=headerlink href=#Fiber-又是什么></a>Fiber 又是什么</h2><p>现在再引入 Fiber 就很容易了。<br>Fiber 可以理解成:<blockquote><p>某个插件这一次运行的“工作档案”。<br>里面记录着:</blockquote><ul><li>这个插件是谁;<li>它在等哪些服务;<li>它现在有没有启动;<li>它注册过什么东西;<li>卸载时要清理什么;<li>它是否启动失败。<br>一个插件大致会经历<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br></pre><td class=code><pre><span class=line>等待条件</span><br><span class=line> ↓</span><br><span class=line>正在启动</span><br><span class=line> ↓</span><br><span class=line>正常运行</span><br><span class=line> ↓</span><br><span class=line>正在清理</span><br><span class=line> ↓</span><br><span class=line>已经卸载</span><br></pre></table></figure>对应的技术名称是:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>PENDING</span><br><span class=line>→ LOADING</span><br><span class=line>→ ACTIVE</span><br><span class=line>→ UNLOADING</span><br><span class=line>→ DISPOSED</span><br></pre></table></figure>所以 Fiber 不是线程,也不是子进程。<br>它只是插件的一份“生命周期档案”。</ul><h3 id=插件怎么插手系统流程><a class=headerlink href=#插件怎么插手系统流程 title=插件怎么插手系统流程></a>插件怎么插手系统流程</h3><p>有些插件提供能力,比如文件系统。<br>另一些插件不提供新能力,只想在某个流程中插一脚。<br>例如权限插件想在执行 Bash 前检查命令:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br></pre><td class=code><pre><span class=line>模型请求执行 rm ...</span><br><span class=line> ↓</span><br><span class=line>权限插件检查</span><br><span class=line> ↓</span><br><span class=line>允许:继续执行</span><br><span class=line>拒绝:直接返回错误</span><br></pre></table></figure><p>这个过程很像高速公路收费站:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br></pre><td class=code><pre><span class=line>请求</span><br><span class=line> → 审批站</span><br><span class=line> → 权限站</span><br><span class=line> → 超时站</span><br><span class=line> → 日志站</span><br><span class=line> → 真正执行</span><br></pre></table></figure><p>每一站都可以:<ul><li>检查请求;<li>修改请求;<li>记录请求;<li>放行;<li>拒绝继续。<br>在代码里,放行通常是调用:<figure class="highlight ts"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line><span class="title function_">next</span>()</span><br></pre></table></figure>不调用 <code>next()</code>,就表示到此为止。<br>这就是它所谓的 <code>waterfall</code>。本质上就是一条可插拔的中间件链。</ul><h2 id=Bundle-和-Profile-又是什么><a title="Bundle 和 Profile 又是什么" class=headerlink href=#Bundle-和-Profile-又是什么></a>Bundle 和 Profile 又是什么</h2><p>这里最容易被名词绕晕。<h3 id=Plugin-是员工><a title="Plugin 是员工" class=headerlink href=#Plugin-是员工></a>Plugin 是员工</h3><p>真正执行工作的代码。<h3 id=Bundle-是部门安装包><a title="Bundle 是部门安装包" class=headerlink href=#Bundle-是部门安装包></a>Bundle 是部门安装包</h3><p>一个 Bundle 可能一次带来很多插件,例如:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br></pre><td class=code><pre><span class=line>Web Bundle</span><br><span class=line>├── Web 服务器插件</span><br><span class=line>├── 浏览器通信插件</span><br><span class=line>├── 聊天界面插件</span><br><span class=line>├── 设置页面插件</span><br><span class=line>└── Web 启动插件</span><br></pre></table></figure><p>Profile 是公司组织方案<br>比如:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line>web Profile</span><br><span class=line>├── 基础 Bundle</span><br><span class=line>└── Web Bundle</span><br></pre></table></figure><p>而:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line>headless Profile</span><br><span class=line>├── 基础 Bundle</span><br><span class=line>└── 命令行 Bundle</span><br></pre></table></figure><p>因此:<figure class="highlight bash"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line>dsh --profile web</span><br></pre></table></figure><p>可以理解成:<blockquote><p>按照 Web 这套组织方案,把对应部门和员工全部组装起来。</blockquote><h2 id=安装一个插件时发生什么><a class=headerlink href=#安装一个插件时发生什么 title=安装一个插件时发生什么></a>安装一个插件时发生什么</h2><p>执行:<figure class="highlight bash"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line>dsh plugin --profile web add some-plugin</span><br></pre></table></figure><p>大致等于:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>1. 用 pnpm 下载 npm 包</span><br><span class=line>2. 查看这个包有没有声明自己是 DSH Bundle</span><br><span class=line>3. 找到它携带的插件配置</span><br><span class=line>4. 把它加入 web Profile</span><br><span class=line>5. 下次启动时加载其中的插件</span><br></pre></table></figure><p>大概是这么个逻辑</div><footer class=post-footer><div class=post-eof></div></footer></article></div><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2026/08/09/%E6%9D%A5%E5%AD%A6%E4%B9%A0%E4%B8%8Bpi-agent%E7%9A%84%E5%8E%9F%E7%90%86/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2026/08/09/%E6%9D%A5%E5%AD%A6%E4%B9%A0%E4%B8%8Bpi-agent%E7%9A%84%E5%8E%9F%E7%90%86/ itemprop=url>来学习下pi agent的原理</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2026-08-09 21:23:24 / 修改时间:21:25:36" datetime=2026-08-09T21:23:24+08:00>2026-08-09</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/LLM/ itemprop=url rel=index><span itemprop=name>LLM</span></a> </span></span><span class="post-meta-item cloudflare-page-counter" data-title="来学习下pi agent的原理" data-increment=false data-path=/2026/08/09/%E6%9D%A5%E5%AD%A6%E4%B9%A0%E4%B8%8Bpi-agent%E7%9A%84%E5%8E%9F%E7%90%86/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=cloudflare-page-counter-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2026/08/09/%E6%9D%A5%E5%AD%A6%E4%B9%A0%E4%B8%8Bpi-agent%E7%9A%84%E5%8E%9F%E7%90%86/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2026/08/09/来学习下pi-agent的原理/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>之前也偶尔用户pi agent这个工具,当然这个还是个很庞大的系统,我也只能一点点学<br>首先是工具系统,默认的核心工具主要是四个 <code>read</code>,<code>write</code>,<code>edit</code>,<code>bash</code><h3 id=read-主要是读取文件><a title="read 主要是读取文件" class=headerlink href=#read-主要是读取文件></a>read 主要是读取文件</h3><p>输入结构式这样<figure class="highlight json"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br><span class=line>14</span><br><span class=line>15</span><br><span class=line>16</span><br><span class=line>17</span><br></pre><td class=code><pre><span class=line><span class=punctuation>{</span></span><br><span class=line> <span class=attr>"path"</span><span class=punctuation>:</span> <span class=string>"src/app.ts"</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"offset"</span><span class=punctuation>:</span> <span class=number>1</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"limit"</span><span class=punctuation>:</span> <span class=number>200</span></span><br><span class=line><span class=punctuation>}</span></span><br><span class=line>- path:相对或绝对路径</span><br><span class=line>- offset:从第几行开始,<span class=number>1</span> 开始计数</span><br><span class=line>- limit:最多读取多少行</span><br><span class=line>内部的原理大致是</span><br><span class=line>```text</span><br><span class=line>解析路径</span><br><span class=line>→ 检查文件是否可读</span><br><span class=line>→ 判断是文本还是图片</span><br><span class=line>→ 读取内容</span><br><span class=line>→ 按 offset/limit 截取</span><br><span class=line>→ 限制输出大小</span><br><span class=line>→ 返回给模型</span><br></pre></table></figure><p>对于文本,Pi 将文件按照 UTF-8 解码并拆分为行。默认最多返回前 2000 行或 50KB,哪个先达到就按哪个截断,并告诉模型下一次应该使用哪个 offset 继续读取。<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line>[Showing lines 1-2000 of 3540. Use offset=2001 to continue.]</span><br></pre></table></figure><h3 id=write-创建文件或完整覆盖><a title="write 创建文件或完整覆盖" class=headerlink href=#write-创建文件或完整覆盖></a>write 创建文件或完整覆盖</h3><p>输入<figure class="highlight json"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br></pre><td class=code><pre><span class=line><span class=punctuation>{</span></span><br><span class=line> <span class=attr>"path"</span><span class=punctuation>:</span> <span class=string>"src/Hello.php"</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"content"</span><span class=punctuation>:</span> <span class=string>"&LT?php\n\necho \"hello\";\n"</span></span><br><span class=line><span class=punctuation>}</span></span><br></pre></table></figure><p>主要原理<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>解析目标路径</span><br><span class=line>→ 创建不存在的父目录</span><br><span class=line>→ 进入该文件的 mutation queue</span><br><span class=line>→ 完整写入 content</span><br><span class=line>→ 返回写入结果</span><br></pre></table></figure><p>如果文件已经存在,则完整覆盖。它不是“追加”,也不是“局部修改”。<br>Pi 会针对同一个文件建立 mutation queue,防止多个并行工具同时修改同一个文件导致内容互相覆盖:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>write A ──────┐</span><br><span class=line> ├→ 同一个文件顺序执行</span><br><span class=line>edit A ──────┘</span><br><span class=line></span><br><span class=line>write B ─────────→ 不同文件可以独立处理</span><br></pre></table></figure><h3 id=edit-精确替换已有代码><a title="edit 精确替换已有代码" class=headerlink href=#edit-精确替换已有代码></a>edit 精确替换已有代码</h3><p>这是四个工具中设计最讲究的一个。<br>输入<br>当前 Pi 支持一次提交多个互不重叠的修改:<figure class="highlight json"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br></pre><td class=code><pre><span class=line><span class=punctuation>{</span></span><br><span class=line> <span class=attr>"path"</span><span class=punctuation>:</span> <span class=string>"src/UserService.php"</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"edits"</span><span class=punctuation>:</span> <span class=punctuation>[</span></span><br><span class=line> <span class=punctuation>{</span></span><br><span class=line> <span class=attr>"oldText"</span><span class=punctuation>:</span> <span class=string>"public function find($id)"</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"newText"</span><span class=punctuation>:</span> <span class=string>"public function find(int $id): ?User"</span></span><br><span class=line> <span class=punctuation>}</span><span class=punctuation>,</span></span><br><span class=line> <span class=punctuation>{</span></span><br><span class=line> <span class=attr>"oldText"</span><span class=punctuation>:</span> <span class=string>"return $this->users[$id];"</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"newText"</span><span class=punctuation>:</span> <span class=string>"return $this->users[$id] ?? null;"</span></span><br><span class=line> <span class=punctuation>}</span></span><br><span class=line> <span class=punctuation>]</span></span><br><span class=line><span class=punctuation>}</span></span><br></pre></table></figure><p>内部原理<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br></pre><td class=code><pre><span class=line>读取原文件</span><br><span class=line>→ 去掉 BOM</span><br><span class=line>→ 将 CRLF/CR 统一成 LF</span><br><span class=line>→ 在原始文件中寻找每个 oldText</span><br><span class=line>→ 检查每段是否唯一、是否重叠</span><br><span class=line>→ 执行全部替换</span><br><span class=line>→ 恢复原来的换行符和 BOM</span><br><span class=line>→ 写回文件</span><br><span class=line>→ 生成 diff 和 unified patch</span><br></pre></table></figure><p>关键要求是:oldText 必须精确匹配,而且在原文件里唯一。<br>例如文件中有两个:<figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line><span class=keyword>return</span> <span class=literal>null</span>;</span><br></pre></table></figure><p>模型如果只提交:<figure class="highlight json"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br></pre><td class=code><pre><span class=line><span class=punctuation>{</span></span><br><span class=line> <span class=attr>"oldText"</span><span class=punctuation>:</span> <span class=string>"return null;"</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"newText"</span><span class=punctuation>:</span> <span class=string>"throw new RuntimeException();"</span></span><br><span class=line><span class=punctuation>}</span></span><br></pre></table></figure><p>工具会拒绝,因为不知道应该修改哪一个。<br>模型必须提供足够的上下文:<figure class="highlight json"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br></pre><td class=code><pre><span class=line><span class=punctuation>{</span></span><br><span class=line> <span class=attr>"oldText"</span><span class=punctuation>:</span> <span class=string>"public function load(): ?User\n{\n return null;\n}"</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"newText"</span><span class=punctuation>:</span> <span class=string>"public function load(): ?User\n{\n return $this->repository->first();\n}"</span></span><br><span class=line><span class=punctuation>}</span></span><br></pre></table></figure><p>为什么采用精确替换<ul><li>它相当于一种轻量级“乐观锁”:<li>模型看到文件版本 A<li>模型根据 A 生成 oldText<li>如果调用工具前文件被改成版本 B<li>oldText 匹配失败<li>工具拒绝覆盖,要求模型重新读取<br>这比让模型直接按行号修改更安全,因为文件新增一行后,行号可能全部偏移。<br>执行成功后,Pi 同时生成:<li>面向终端显示的彩色 diff<li>标准 unified patch<li>第一处变化的行号</ul><h3 id=bash-给模型提供“手脚”><a title="bash 给模型提供“手脚”" class=headerlink href=#bash-给模型提供“手脚”></a>bash 给模型提供“手脚”</h3><p>输入<figure class="highlight json"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br></pre><td class=code><pre><span class=line><span class=punctuation>{</span></span><br><span class=line> <span class=attr>"command"</span><span class=punctuation>:</span> <span class=string>"php -l src/UserService.php && php tests/run.php"</span><span class=punctuation>,</span></span><br><span class=line> <span class=attr>"timeout"</span><span class=punctuation>:</span> <span class=number>30</span></span><br><span class=line><span class=punctuation>}</span></span><br></pre></table></figure><p>原理:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br></pre><td class=code><pre><span class=line>找到当前平台的 Shell</span><br><span class=line>→ 在工作目录启动子进程</span><br><span class=line>→ 注入环境变量</span><br><span class=line>→ 同时监听 stdout/stderr</span><br><span class=line>→ 实时把输出推送到 TUI</span><br><span class=line>→ 等待退出码</span><br><span class=line>→ 将结果返回给模型</span><br></pre></table></figure><p>它可以完成:<ul><li><code>rg</code>、<code>find</code>、<code>ls</code> 搜索项目<li>运行测试<li>调用编译器<li>执行 Git 命令<li>安装依赖<li>启动构建脚本<li>执行任意系统程序<li>输出处理<br>与 <code>read</code> 保留“开头”不同,<code>bash</code> 更适合保留“结尾”。<br>因为测试、编译和日志输出的错误通常在末尾。因此 Pi 保留最后 2000 行或最后 50KB。如果发生截断,完整输出会另外保存到临时文件。</ul><h3 id=四个工具如何协作><a class=headerlink href=#四个工具如何协作 title=四个工具如何协作></a>四个工具如何协作</h3><p>假设用户说:<br>给项目增加一个 /health 接口并运行测试。<p>模型可能按下面的流程工作:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br><span class=line>14</span><br><span class=line>15</span><br><span class=line>16</span><br><span class=line>17</span><br><span class=line>18</span><br><span class=line>19</span><br><span class=line>20</span><br><span class=line>21</span><br><span class=line>22</span><br><span class=line>23</span><br></pre><td class=code><pre><span class=line>1. bash</span><br><span class=line> rg "Route|router" src</span><br><span class=line></span><br><span class=line>2. read</span><br><span class=line> 读取找到的路由文件</span><br><span class=line></span><br><span class=line>3. edit</span><br><span class=line> 精确插入 /health 路由</span><br><span class=line></span><br><span class=line>4. write</span><br><span class=line> 创建新的 HealthController.php</span><br><span class=line></span><br><span class=line>5. bash</span><br><span class=line> php -l ... && php tests/run.php</span><br><span class=line></span><br><span class=line>6. read</span><br><span class=line> 如果测试失败,读取相关源文件</span><br><span class=line></span><br><span class=line>7. edit</span><br><span class=line> 修复问题</span><br><span class=line></span><br><span class=line>8. bash</span><br><span class=line> 再次运行测试</span><br></pre></table></figure><p>这就是 Coding Agent 的核心闭环:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>观察(read/bash)</span><br><span class=line>→ 决策(LLM)</span><br><span class=line>→ 修改(edit/write)</span><br><span class=line>→ 验证(bash)</span><br><span class=line>→ 再观察</span><br></pre></table></figure><p>大致学一下这个工具的工具逻辑</div><footer class=post-footer><div class=post-eof></div></footer></article></div><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2026/08/02/%E5%A6%82%E4%BD%95%E5%9C%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%B8%AD%E8%BE%93%E5%87%BA%E8%BF%9B%E5%BA%A6%E6%9D%A1/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2026/08/02/%E5%A6%82%E4%BD%95%E5%9C%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%B8%AD%E8%BE%93%E5%87%BA%E8%BF%9B%E5%BA%A6%E6%9D%A1/ itemprop=url>如何在命令行中输出进度条</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2026-08-02 21:26:43 / 修改时间:21:29:37" datetime=2026-08-02T21:26:43+08:00>2026-08-02</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/%E5%B0%8F%E6%8A%80%E5%B7%A7/ itemprop=url rel=index><span itemprop=name>小技巧</span></a> </span></span><span class="post-meta-item cloudflare-page-counter" data-increment=false data-path=/2026/08/02/%E5%A6%82%E4%BD%95%E5%9C%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%B8%AD%E8%BE%93%E5%87%BA%E8%BF%9B%E5%BA%A6%E6%9D%A1/ data-title=如何在命令行中输出进度条 title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=cloudflare-page-counter-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2026/08/02/%E5%A6%82%E4%BD%95%E5%9C%A8%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%B8%AD%E8%BE%93%E5%87%BA%E8%BF%9B%E5%BA%A6%E6%9D%A1/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2026/08/02/如何在命令行中输出进度条/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>之前就比较好奇,命令行一般输出都是往后追加,好像不知道怎么做覆盖更新,但是很多比较厉害的shell脚本都有那种进度条,甚至整个重绘<br>所以就来看下,怎么在命令行里输出个会变的进度条,<br>比如我在命令行中输出两行<figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line><span class=keyword>echo</span> <span class=string>"111\n"</span>;</span><br><span class=line><span class=keyword>echo</span> <span class=string>"222\n"</span>;</span><br><span class=line><span class=keyword>exit</span>;</span><br></pre></table></figure><p>最简单就是这样子,那如果想把111改成222呢<br>我们发现”\n”是换行,那”\r”其实是原地移动到行首<br>可以再看下<figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br></pre><td class=code><pre><span class=line><span class=keyword>echo</span> <span class=string>"111\r"</span>;</span><br><span class=line><span class="title function_ invoke__">usleep</span>(<span class=number>1000</span>*<span class=number>1000</span>);</span><br><span class=line><span class=keyword>echo</span> <span class=string>"222\n"</span>;</span><br><span class=line><span class=keyword>exit</span>;</span><br></pre></table></figure><p>加了sleep是因为闪太快了看不到,这样就能看到这一行就重新刷新了<br>然后就可以看下进度条可以怎么输出了<figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br></pre><td class=code><pre><span class=line><span class=keyword>for</span> (<span class=variable>$i</span> = <span class=number>0</span>; <span class=variable>$i</span> <= <span class=number>50</span>; <span class=variable>$i</span>++) {</span><br><span class=line> <span class="title function_ invoke__">printf</span>(<span class=string>"progress: [%-50s] %d%%\r"</span>, <span class="title function_ invoke__">str_repeat</span>(<span class=string>'#'</span>,<span class=variable>$i</span>), <span class=variable>$i</span> * <span class=number>2</span>);</span><br><span class=line> <span class="title function_ invoke__">usleep</span>(<span class=number>1000</span> * <span class=number>100</span>);</span><br><span class=line>}</span><br><span class=line><span class=keyword>echo</span> <span class=string>"\n"</span>;</span><br><span class=line><span class=keyword>echo</span> <span class=string>"Done.\n"</span>;</span><br></pre></table></figure><p>首先是解释下这段的含义<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>"progress: [%-50s] %d%%\r"</span><br><span class=line> └──┬──┘ │ │ └─ 回到当前行开头</span><br><span class=line> │ │ └──── 输出一个真正的 %</span><br><span class=line> │ └────── 输出整数</span><br><span class=line> └──────────── 输出宽度为 50 的字符串</span><br></pre></table></figure><p>感觉又变成了一个视觉游戏,以为是逐渐的在往后画<br>其实是一直在刷新这个进度条<br>首先是定义一个长度是50个字符的输出,用空格补全,然后会输出对应百分比,比如2%<br>就对应的是一个井号,然后用”\r”回到行首重绘<br>实际的就是第一次画一个#号,第二次画两个#号<br>这里最大的重点就是要让部分字符看着在变,部分看着不变,才能形成这种视觉假象<br>比如这里的50个字符长度,还有对应的”%”符号<br>否则就会变成一直在跳的了<br>对应的动的部分就是#号的增加,对应百分比数值也在往上涨<br>不过这里有点小问题,不知道有没有发现,它的数字没有定义位数<br>那么在达到100%的时候其实是有一点跳跃的<p>那如果想要改多行怎么办呢<br>就需要用ANSI 控制序列让光标向上移动若干行<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line>任务 A:[######## ] 40%</span><br><span class=line>任务 B:[############ ] 60%</span><br><span class=line>总进度:[########## ] 50%</span><br></pre></table></figure><p>光标此时位于这三行下面。下一次刷新前,先让光标向上移动三行:<figure class="highlight shell"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line>ESC [ 3 A</span><br></pre></table></figure><p>在php中可以写成<figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line><span class=keyword>echo</span> <span class=string>"\033[3A"</span>;</span><br></pre></table></figure><p>最简单的就是<figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br></pre><td class=code><pre><span class=line><span class=keyword>echo</span> <span class=string>"111\n"</span>;</span><br><span class=line><span class=keyword>echo</span> <span class=string>"222\n"</span>;</span><br><span class=line><span class=keyword>echo</span> <span class=string>"333\n"</span>;</span><br><span class=line><span class=keyword>echo</span> <span class=string>"\033[3A"</span>;</span><br><span class=line><span class="title function_ invoke__">usleep</span>(<span class=number>1000</span>*<span class=number>1000</span>);</span><br><span class=line><span class=keyword>echo</span> <span class=string>"444\n"</span>;</span><br></pre></table></figure><p>这样就会把前面的111,222,333给干掉,重新输出444<br>来个像样点的脚本就是<figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br><span class=line>13</span><br><span class=line>14</span><br><span class=line>15</span><br><span class=line>16</span><br><span class=line>17</span><br><span class=line>18</span><br><span class=line>19</span><br><span class=line>20</span><br><span class=line>21</span><br><span class=line>22</span><br><span class=line>23</span><br><span class=line>24</span><br><span class=line>25</span><br><span class=line>26</span><br><span class=line>27</span><br><span class=line>28</span><br><span class=line>29</span><br><span class=line>30</span><br><span class=line>31</span><br><span class=line>32</span><br><span class=line>33</span><br><span class=line>34</span><br><span class=line>35</span><br><span class=line>36</span><br><span class=line>37</span><br><span class=line>38</span><br><span class=line>39</span><br><span class=line>40</span><br><span class=line>41</span><br><span class=line>42</span><br></pre><td class=code><pre><span class=line><span class=meta>&LT?php</span></span><br><span class=line></span><br><span class=line><span class=function><span class=keyword>function</span> <span class=title>progressBar</span>(<span class=params><span class=keyword>int</span> <span class=variable>$percent</span>, <span class=keyword>int</span> <span class=variable>$width</span> = <span class=number>30</span></span>): <span class=title>string</span></span></span><br><span class=line><span class=function></span>{</span><br><span class=line> <span class=variable>$percent</span> = <span class="title function_ invoke__">max</span>(<span class=number>0</span>, <span class="title function_ invoke__">min</span>(<span class=number>100</span>, <span class=variable>$percent</span>));</span><br><span class=line> <span class=variable>$filled</span> = (<span class=keyword>int</span>) <span class="title function_ invoke__">floor</span>(<span class=variable>$percent</span> * <span class=variable>$width</span> / <span class=number>100</span>);</span><br><span class=line></span><br><span class=line> <span class=keyword>return</span> <span class="title function_ invoke__">sprintf</span>(</span><br><span class=line> <span class=string>"[%-<span class=subst>{$width}</span>s] %3d%%"</span>,</span><br><span class=line> <span class="title function_ invoke__">str_repeat</span>(<span class=string>'#'</span>, <span class=variable>$filled</span>),</span><br><span class=line> <span class=variable>$percent</span></span><br><span class=line> );</span><br><span class=line>}</span><br><span class=line></span><br><span class=line><span class=variable>$lineCount</span> = <span class=number>3</span>;</span><br><span class=line></span><br><span class=line><span class=keyword>for</span> (<span class=variable>$i</span> = <span class=number>0</span>; <span class=variable>$i</span> <= <span class=number>100</span>; <span class=variable>$i</span>++) {</span><br><span class=line> <span class=variable>$taskA</span> = <span class=variable>$i</span>;</span><br><span class=line> <span class=variable>$taskB</span> = <span class="title function_ invoke__">min</span>(<span class=number>100</span>, <span class=variable>$i</span> * <span class=number>2</span>);</span><br><span class=line> <span class=variable>$total</span> = (<span class=keyword>int</span>) ((<span class=variable>$taskA</span> + <span class=variable>$taskB</span>) / <span class=number>2</span>);</span><br><span class=line></span><br><span class=line> <span class=comment>// 第一次输出前不需要移动光标</span></span><br><span class=line> <span class=keyword>if</span> (<span class=variable>$i</span> > <span class=number>0</span>) {</span><br><span class=line> <span class="title function_ invoke__">printf</span>(<span class=string>"\033[%dA"</span>, <span class=variable>$lineCount</span>);</span><br><span class=line> }</span><br><span class=line></span><br><span class=line> <span class=variable>$lines</span> = [</span><br><span class=line> <span class=string>"任务 A:"</span> . <span class="title function_ invoke__">progressBar</span>(<span class=variable>$taskA</span>),</span><br><span class=line> <span class=string>"任务 B:"</span> . <span class="title function_ invoke__">progressBar</span>(<span class=variable>$taskB</span>),</span><br><span class=line> <span class=string>"总进度:"</span> . <span class="title function_ invoke__">progressBar</span>(<span class=variable>$total</span>),</span><br><span class=line> ];</span><br><span class=line></span><br><span class=line> <span class=keyword>foreach</span> (<span class=variable>$lines</span> <span class=keyword>as</span> <span class=variable>$line</span>) {</span><br><span class=line> <span class=comment>// 回到行首并清除当前整行</span></span><br><span class=line> <span class=keyword>echo</span> <span class=string>"\r\033[2K"</span>;</span><br><span class=line> <span class=keyword>echo</span> <span class=variable>$line</span>;</span><br><span class=line> <span class=keyword>echo</span> PHP_EOL;</span><br><span class=line> }</span><br><span class=line></span><br><span class=line> <span class="title function_ invoke__">fflush</span>(STDOUT);</span><br><span class=line> <span class="title function_ invoke__">usleep</span>(<span class=number>100000</span>);</span><br><span class=line>}</span><br></pre></table></figure><p>这里的符号代表的含义<table><thead><tr><th>控制序列<th>作用<tbody><tr><td><code>\r</code><td>回到当前行行首<tr><td><code>\033[2K</code><td>清除当前整行<tr><td><code>\033[3A</code><td>光标向上移动三行<tr><td><code>\033[1A</code><td>光标向上移动一行<tr><td><code>\033[1B</code><td>光标向下移动一行<tr><td>\033 表示 ESC 字符,所以:<td></table><figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line><span class=keyword>echo</span> <span class=string>"\033[3A"</span>;</span><br></pre></table></figure><p>发送给终端的实际含义是:<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line>ESC + [3A</span><br></pre></table></figure><p>也就是“光标向上移动三行”。<br>还是比较神奇的东西<br>以前一直没搞明白,刚好这次想到了<br>现在很多想claude code,包括opencode,pi等都是搞成了命令行的<br>这个大概就是这些命令行工具的基础<br>像opencode是使用的<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line>@opentui/core</span><br><span class=line>@opentui/solid</span><br><span class=line>solid-js</span><br></pre></table></figure><p>pi则是使用<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br></pre><td class=code><pre><span class=line>@earendil-works/pi-tui</span><br><span class=line>其他的框架还有</span><br></pre></table></figure><table><thead><tr><th>语言<th>开源库<th>定位<tbody><tr><td>TypeScript<td><a href=https://github.com/anomalyco/opentui rel=noopener target=_blank>OpenTUI</a><td>OpenCode 使用的完整 TUI<tr><td>TypeScript<td><a href=https://github.com/badlogic/pi-mono/tree/main/packages/tui rel=noopener target=_blank>pi-tui</a><td>Pi 使用的轻量差量渲染<tr><td>JavaScript<td><a href=https://github.com/vadimdemedes/ink rel=noopener target=_blank>Ink</a><td>使用 React 编写 CLI<tr><td>JavaScript<td><code>cli-progress</code><td>单个或多个进度条<tr><td>Go<td><a href=https://github.com/charmbracelet/bubbletea rel=noopener target=_blank>Bubble Tea</a><td>Elm 风格 TUI 框架<tr><td>Rust<td><a href=https://github.com/ratatui/ratatui rel=noopener target=_blank>Ratatui</a><td>Rust 生态常用 TUI<tr><td>PHP<td><a href=https://symfony.com/doc/current/console.html#output-sections rel=noopener target=_blank>Symfony Console</a><td>进度条、表格和多区域刷新<tr><td>PHP 里最省事的是 Symfony Console 的 section()<td><td></table><figure class="highlight php"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br><span class=line>12</span><br></pre><td class=code><pre><span class=line><span class=keyword>use</span> <span class=title>Symfony</span>\<span class=title>Component</span>\<span class=title>Console</span>\<span class=title>Output</span>\<span class=title>ConsoleOutput</span>;</span><br><span class=line></span><br><span class=line><span class=variable>$output</span> = <span class=keyword>new</span> <span class="title class_">ConsoleOutput</span>();</span><br><span class=line><span class=variable>$section</span> = <span class=variable>$output</span>-><span class="title function_ invoke__">section</span>();</span><br><span class=line></span><br><span class=line><span class=variable>$section</span>-><span class="title function_ invoke__">writeln</span>(<span class=string>"任务 A:10%\n任务 B:20%\n任务 C:30%"</span>);</span><br><span class=line></span><br><span class=line><span class="title function_ invoke__">sleep</span>(<span class=number>1</span>);</span><br><span class=line></span><br><span class=line><span class=variable>$section</span>-><span class="title function_ invoke__">overwrite</span>(</span><br><span class=line> <span class=string>"任务 A:40%\n任务 B:50%\n任务 C:60%"</span></span><br><span class=line>);</span><br></pre></table></figure></div><footer class=post-footer><div class=post-eof></div></footer></article></div><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2026/07/26/%E8%81%94%E6%83%B3-G400-%E5%AE%89%E8%A3%85-Windows-7/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2026/07/26/%E8%81%94%E6%83%B3-G400-%E5%AE%89%E8%A3%85-Windows-7/ itemprop=url>联想 G400 安装 Windows 7 折腾记录</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2026-07-26 22:00:00 / 修改时间:18:13:16" datetime=2026-07-26T22:00:00+08:00>2026-07-26</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Windows/ itemprop=url rel=index><span itemprop=name>Windows</span></a> </span>, <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/Windows/%E5%B0%8F%E6%8A%80%E5%B7%A7/ itemprop=url rel=index><span itemprop=name>小技巧</span></a> </span></span><span class="post-meta-item cloudflare-page-counter" data-title="联想 G400 安装 Windows 7 折腾记录" data-increment=false data-path=/2026/07/26/%E8%81%94%E6%83%B3-G400-%E5%AE%89%E8%A3%85-Windows-7/ title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=cloudflare-page-counter-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2026/07/26/%E8%81%94%E6%83%B3-G400-%E5%AE%89%E8%A3%85-Windows-7/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2026/07/26/联想-G400-安装-Windows-7/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>最近给一台联想 G400 重装 Windows 7。本来以为只是做个启动盘、装好系统就结束了,实际操作时却遇到了驱动缺失、旧版 IE 无法打开部分网站、Windows Update 报错,以及显卡驱动依赖 .NET Framework 等一连串问题。这里把完整过程和用到的资料整理一下,方便以后再遇到类似的老电脑时查阅。<p>先提醒一句:Windows 7 已于 2020 年 1 月 14 日结束支持,不再获得常规安全更新;Chrome 109 也早已停止更新。因此,这套方案更适合需要兼容老软件或老硬件的场景,不建议把它作为长期联网、登录重要账号或进行支付操作的主力系统。<h2 id=一、安装前的准备><a class=headerlink href=#一、安装前的准备 title=一、安装前的准备></a>一、安装前的准备</h2><h3 id=1-下载-Windows-7-SP1-镜像><a title="1. 下载 Windows 7 SP1 镜像" class=headerlink href=#1-下载-Windows-7-SP1-镜像></a>1. 下载 Windows 7 SP1 镜像</h3><p>我使用的是 Windows 7 SP1 原版镜像,可以从 <a href=https://msdn.itellyou.cn/ rel=noopener target=_blank>MSDN,我告诉你</a> 查找。<p>需要注意的是,这个网站不是微软官方网站,而是第三方原版软件信息收录站。下载时应选择与授权和硬件相符的版本,并核对镜像的 SHA-1 等校验值,避免使用被二次修改、捆绑软件或来源不明的镜像。<p>联想 G400 通常可以安装 64 位系统。如果机器内存很小,或者有必须使用 32 位系统的老软件,再根据实际情况选择 x86 版本。后面下载补丁和驱动时,系统架构也必须保持一致。<h3 id=2-提前下载驱动><a title="2. 提前下载驱动" class=headerlink href=#2-提前下载驱动></a>2. 提前下载驱动</h3><p>Windows 7 对很多硬件并不能做到安装后自动识别,最麻烦的情况是系统装好了,却因为有线网卡和无线网卡都没有驱动而无法联网。因此,重装前最好先从 <a href=https://newsupport.lenovo.com.cn/driveList.html?fromsource=driveList&selname=Lenovo%20G400 rel=noopener target=_blank>联想 G400 驱动下载页面</a> 下载对应版本的驱动,放到另一个 U 盘中。<p>建议至少准备这些驱动:<ul><li>芯片组驱动;<li>有线网卡和无线网卡驱动;<li>核芯显卡和独立显卡驱动;<li>声卡、触控板、读卡器等驱动。</ul><p>G400 有不同的硬件配置,最好根据机器背面的具体型号或主机编号查找,不要只看系列名称。网卡驱动尤其可以多准备一个可能的版本,以免装完系统后完全无法联网。<h3 id=3-提前下载补丁和常用软件><a title="3. 提前下载补丁和常用软件" class=headerlink href=#3-提前下载补丁和常用软件></a>3. 提前下载补丁和常用软件</h3><p>为了避免装好系统后才发现网站打不开,建议把下面这些内容也提前放进 U 盘:<ul><li>.NET Framework 4 独立安装包;<li>IE11 安装包;<li>本文后面提到的 Windows 7 补丁;<li>Chrome 109 离线安装包;<li>已下载好的联想官方驱动。</ul><h2 id=二、制作启动-U-盘并安装系统><a title="二、制作启动 U 盘并安装系统" class=headerlink href=#二、制作启动-U-盘并安装系统></a>二、制作启动 U 盘并安装系统</h2><p>我使用 UltraISO 将 Windows 7 SP1 镜像写入 U 盘。操作前一定要确认目标盘符,因为写入过程会清空 U 盘中的原有数据。<p>制作完成后,从联想 G400 的启动菜单中选择 U 盘,按照安装向导完成系统安装即可。如果进入安装界面后出现键盘、鼠标或 U 盘突然无法使用的情况,可以先换到 USB 2.0 接口再试;Windows 7 安装环境对 USB 3.0 的原生支持并不完善。<p>分区或格式化系统盘前,务必确认重要文件已经备份。安装完成后也不要急着联网,先把基础驱动和补丁装好。<h2 id=三、安装驱动和-NET-Framework-4><a title="三、安装驱动和 .NET Framework 4" class=headerlink href=#三、安装驱动和-NET-Framework-4></a>三、安装驱动和 .NET Framework 4</h2><p>驱动建议按下面的顺序安装:<ol><li>芯片组驱动;<li>有线网卡或无线网卡驱动;<li>核芯显卡和独立显卡驱动;<li>声卡、触控板、读卡器等其他驱动。</ol><p>这次安装显卡驱动时,安装程序提示缺少 .NET Framework 4。可以从微软官方下载 <a href=https://www.microsoft.com/zh-cn/download/details.aspx?id=17718 rel=noopener target=_blank>.NET Framework 4 独立安装程序</a>,安装并重启后,再继续安装显卡驱动。<p>驱动全部安装完成后,可以打开“设备管理器”,检查是否还存在带黄色感叹号的设备。<h2 id=四、先安装-Windows-7-汇总补丁><a title="四、先安装 Windows 7 汇总补丁" class=headerlink href=#四、先安装-Windows-7-汇总补丁></a>四、先安装 Windows 7 汇总补丁</h2><p>刚装好的 Windows 7 SP1 与现在的网络环境相差太远,直接使用 Windows Update 往往会失败。可以先手动安装微软的便利汇总补丁 <code>KB3125574</code>,它包含了 Windows 7 SP1 发布之后到 2016 年 4 月之间的大部分更新。<p>这里有一个容易遗漏的前置条件:安装 <code>KB3125574</code> 之前,必须先安装 2015 年 4 月的服务堆栈更新 <code>KB3020369</code>。<p>推荐顺序如下:<ol><li>在 Microsoft Update Catalog 中下载并安装 <a href=https://www.catalog.update.microsoft.com/Search.aspx?q=KB3020369 rel=noopener target=_blank>KB3020369</a>,然后重启;<li>下载并安装 <a href=https://www.catalog.update.microsoft.com/Search.aspx?q=KB3125574 rel=noopener target=_blank>KB3125574</a>,然后再次重启。</ol><p>下载时要认准 Windows 7,并根据当前系统选择 x86 或 x64 包,不要误下成 Windows Server 2008 R2 版本。安装 <code>KB3125574</code> 还需要给系统盘预留至少 4 GB 可用空间。<p>如果提示“此更新不适用于你的计算机”,优先检查以下几项:<ul><li>当前系统是否已经是 Windows 7 SP1;<li>下载的补丁架构是否与系统一致;<li>前置补丁是否已经安装;<li>该补丁是否已经安装,或被更新的补丁取代。</ul><h2 id=五、安装-IE11><a title="五、安装 IE11" class=headerlink href=#五、安装-IE11></a>五、安装 IE11</h2><p>系统补丁安装完成后,可以安装微软提供的 <a href=https://www.microsoft.com/zh-cn/download/details.aspx?id=41628 rel=noopener target=_blank>Windows 7 版 IE11(64 位)</a>。IE11 本身也已经停止支持,这里安装它主要是为了改善老系统的网页兼容性,并补齐部分旧软件依赖,不建议把它当作日常浏览器。<p>如果刚装好 Windows 7 时打不开补丁目录或下载页面,可以在另一台正常联网的电脑上先把安装包下载好,再通过 U 盘复制过去。不要为了打开网站而关闭证书校验或安装来源不明的所谓“证书修复包”。<h2 id=六、解决-Windows-Update-的-80072EFE-错误><a title="六、解决 Windows Update 的 80072EFE 错误" class=headerlink href=#六、解决-Windows-Update-的-80072EFE-错误></a>六、解决 Windows Update 的 80072EFE 错误</h2><p>如果运行 Windows Update 时出现 <code>80072EFE</code>,可以参考<a href=https://www.reddit.com/r/windows7/comments/lnobhu/fix_update_error_80072efe_on_new_installations_of/ rel=noopener target=_blank>这篇 Reddit 讨论</a>,手动安装下面三个补丁:<ol><li><a href=https://www.catalog.update.microsoft.com/Search.aspx?q=KB4490628 rel=noopener target=_blank>KB4490628</a>:2019 年 3 月服务堆栈更新;<li><a href=https://www.catalog.update.microsoft.com/Search.aspx?q=KB4474419 rel=noopener target=_blank>KB4474419</a>:SHA-2 代码签名支持更新;<li><a href=https://www.catalog.update.microsoft.com/Search.aspx?q=KB3138612 rel=noopener target=_blank>KB3138612</a>:Windows Update Client 更新。</ol><p>建议按上面的顺序逐个安装。遇到提示需要重启时就先重启,再继续安装下一个;三个补丁安装完毕后,再次重启并运行 Windows Update。<p>如果 Windows Update 仍然失败,可以先确认系统时间、时区是否正确,并检查有线或无线网络是否稳定。由于 Windows 7 已结束支持,即使更新功能恢复,也不能把它理解为系统重新获得了完整、持续的安全支持。<h2 id=七、浏览器选择><a class=headerlink href=#七、浏览器选择 title=七、浏览器选择></a>七、浏览器选择</h2><p>Windows 7 能使用的最后一个 Chrome 大版本是 Chrome 109,后续版本已经不再支持 Windows 7。如果确实需要,可以安装 109 版本,但它已经不能获得新的功能和安全修复。<p>因此,Chrome 109 只适合临时访问普通网页或兼容老系统,不要用它登录网银、邮箱等重要账号。离线安装包也应尽量从可信渠道取得,并核对数字签名,不建议随便从软件站下载所谓的“绿色版”或“特别版”。<h2 id=八、完整安装顺序><a class=headerlink href=#八、完整安装顺序 title=八、完整安装顺序></a>八、完整安装顺序</h2><p>最后把这次的操作顺序汇总一下:<ol><li>备份原系统中的重要数据;<li>下载 Windows 7 SP1 镜像并用 UltraISO 制作启动 U 盘;<li>提前准备联想 G400 驱动、系统补丁和离线安装软件;<li>安装 Windows 7 SP1;<li>安装芯片组和网卡驱动;<li>安装 .NET Framework 4,再安装显卡及其他驱动;<li>依次安装 <code>KB3020369</code> 和 <code>KB3125574</code>;<li>安装 IE11;<li>遇到 <code>80072EFE</code> 时,依次安装 <code>KB4490628</code>、<code>KB4474419</code> 和 <code>KB3138612</code>;<li>根据需要安装 Chrome 109,并尽量减少这台机器的联网用途。</ol><p>这次最深的感受是,给老电脑装 Windows 7,真正花时间的并不是系统安装本身,而是提前准备驱动、补齐系统组件和解决更新问题。把驱动和补丁都提前放进 U 盘,整个过程会省心很多。<h2 id=参考资料><a class=headerlink href=#参考资料 title=参考资料></a>参考资料</h2><ul><li><a href=https://www.chiphell.com/thread-2524069-2-1.html rel=noopener target=_blank>Windows 7 安装与更新问题讨论</a><li><a href=https://zhuanlan.zhihu.com/p/1944089407373149968 rel=noopener target=_blank>Windows 7 更新相关整理</a><li><a href=https://www.catalog.update.microsoft.com/ rel=noopener target=_blank>Microsoft Update Catalog</a><li><a href=https://support.google.com/chrome/a/answer/7100626 rel=noopener target=_blank>Google Chrome 浏览器系统要求</a></ul></div><footer class=post-footer><div class=post-eof></div></footer></article></div><div class=post-block><article class=post-content itemscope itemtype=http://schema.org/Article><link href=https://nicksxs.me/2026/07/19/%E8%AE%B0%E4%B8%80%E4%B8%AAgiea%E6%8E%A8%E9%80%81%E5%A4%B1%E8%B4%A5%E7%9A%84%E9%97%AE%E9%A2%98/ itemprop=mainEntityOfPage><span hidden itemprop=author itemscope itemtype=http://schema.org/Person><meta content=/uploads/avatar.jpg itemprop=image><meta content=Nicksxs itemprop=name></span><span hidden itemprop=publisher itemscope itemtype=http://schema.org/Organization><meta content="Nicksxs's Blog" itemprop=name><meta content="learn from zero,技术博客,Nicksxs,史学森" itemprop=description></span><span hidden itemprop=post itemscope itemtype=http://schema.org/CreativeWork><meta content="undefined | Nicksxs's Blog" itemprop=name><meta itemprop=description></span><header class=post-header><h2 itemprop="name headline" class=post-title><a class=post-title-link href=/2026/07/19/%E8%AE%B0%E4%B8%80%E4%B8%AAgiea%E6%8E%A8%E9%80%81%E5%A4%B1%E8%B4%A5%E7%9A%84%E9%97%AE%E9%A2%98/ itemprop=url>记一个gitea推送失败的问题</a></h2><div class=post-meta-container><div class=post-meta><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-calendar"></i> </span><span class=post-meta-item-text>发表于</span> <time itemprop="dateCreated datePublished" title="创建时间:2026-07-19 20:53:14" datetime=2026-07-19T20:53:14+08:00>2026-07-19</time> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-folder"></i> </span><span class=post-meta-item-text>分类于</span> <span itemprop=about itemscope itemtype=http://schema.org/Thing><a href=/categories/git/ itemprop=url rel=index><span itemprop=name>git</span></a> </span></span><span class="post-meta-item cloudflare-page-counter" data-increment=false data-path=/2026/07/19/%E8%AE%B0%E4%B8%80%E4%B8%AAgiea%E6%8E%A8%E9%80%81%E5%A4%B1%E8%B4%A5%E7%9A%84%E9%97%AE%E9%A2%98/ data-title=记一个gitea推送失败的问题 title=阅读次数><span class=post-meta-item-icon><i class="far fa-eye"></i> </span><span class=post-meta-item-text>阅读次数:</span> <span class=cloudflare-page-counter-count></span> </span><span class=post-meta-item><span class=post-meta-item-icon><i class="far fa-comment"></i> </span><span class=post-meta-item-text>Disqus:</span> <a href=/2026/07/19/%E8%AE%B0%E4%B8%80%E4%B8%AAgiea%E6%8E%A8%E9%80%81%E5%A4%B1%E8%B4%A5%E7%9A%84%E9%97%AE%E9%A2%98/#disqus_thread itemprop=discussionUrl title=disqus><span class="post-comments-count disqus-comment-count" data-disqus-identifier=2026/07/19/记一个giea推送失败的问题/ itemprop=commentCount></span></a></span></div></div></header><div class=post-body itemprop=articleBody><p>我的博客的推送一份是在github<br>作为github page,另一份是在自建的gitea上面<br>上周突然就出现推送失败了<br>在gpt5.5老师的指导下一顿查gitea服务器的日志也没查出来原因<br>一开始说是可以尝试从https切换到ssh形式也没起作用<br>服务端日志也没有用的<br>然后这次升级了gpt5.6老师以后,就再问了下<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br></pre><td class=code><pre><span class=line>send-pack: unexpected disconnect while reading sideband packet</span><br><span class=line>Writing objects: 100% (6455/6455), 2.95 MiB | 1.53 MiB/s, done.</span><br><span class=line>Total 6455 (delta 2752), reused 6281 (delta 2580), pack-reused 0</span><br><span class=line>fatal: the remote end hung up unexpectedly</span><br></pre></table></figure><p>这次的日志比较有价值可能<br>另外还有个信息是之前<code>git gc</code>因为仓库的小文件太多了可能<br>然后这次gpt老师给出的方法是<figure class="highlight shell"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br></pre><td class=code><pre><span class=line>http.postBuffer = 16777216</span><br><span class=line>http.version = HTTP/1.1</span><br></pre></table></figure><p>把postBuffer给调大了,然后直接在仓库里执行<figure class="highlight shell"><table><tr><td class=gutter><pre><span class=line>1</span><br></pre><td class=code><pre><span class=line>git -C .deploy_git push --verbose</span><br></pre></table></figure><p>发现直接可以了<br>具体原因分析下来是: 推送产生的请求体约为 2.95 MiB,超过了 Git 默认 1 MiB 的 http.postBuffer。<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br><span class=line>6</span><br><span class=line>7</span><br><span class=line>8</span><br><span class=line>9</span><br><span class=line>10</span><br><span class=line>11</span><br></pre><td class=code><pre><span class=line>推送数据 2.95 MiB</span><br><span class=line> ↓ 超过默认缓冲区 1 MiB</span><br><span class=line>Git 改用 chunked 分块传输</span><br><span class=line> ↓</span><br><span class=line>Traefik / Gitea 链路没有正确处理该请求</span><br><span class=line> ↓</span><br><span class=line>返回 HTTP 200,但响应体为 0</span><br><span class=line> ↓</span><br><span class=line>Git 收不到 receive-pack 的 sideband 结果</span><br><span class=line> ↓</span><br><span class=line>unexpected disconnect</span><br></pre></table></figure><p>因为默认的postBuffer不够大,然后使用了chunked传输,是指一块块传,直到最后一块大小为0<br>然后因为我的gitea可能经过了traefik和gitea中间有不支持的<br>关于postBuffer在git官方文档也有解释<h3 id=http-postBuffer><a class=headerlink href=#http-postBuffer title=http.postBuffer></a>http.postBuffer</h3><figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line>Maximum size in bytes of the buffer used by smart HTTP transports when POSTing data to the remote system. For requests larger than this buffer size, HTTP/1.1 and Transfer-Encoding: chunked is used to avoid creating a massive pack file locally. Default is 1 MiB, which is sufficient for most requests.</span><br><span class=line></span><br><span class=line>Note that raising this limit is only effective for disabling chunked transfer encoding and therefore should be used only where the remote server or a proxy only supports HTTP/1.0 or is noncompliant with the HTTP standard. Raising this is not, in general, an effective solution for most push problems, but can increase memory consumption significantly since the entire buffer is allocated even for small pushes.</span><br></pre></table></figure><p>翻译下<figure class="highlight text"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br><span class=line>4</span><br><span class=line>5</span><br></pre><td class=code><pre><span class=line>Git 使用智能 HTTP 传输协议向远程服务器发送 POST 请求时,所使用缓冲区的最大大小,单位为字节。</span><br><span class=line>当请求大小超过这个缓冲区时,Git 会使用 HTTP/1.1 的 Transfer-Encoding: chunked,也就是分块传输编码,以避免在本地创建一个非常大的 pack 文件。</span><br><span class=line>默认值是 1 MiB,对于大多数请求来说已经足够。</span><br><span class=line>需要注意的是,增大这个值的作用仅仅是停用分块传输编码。因此,只有在远程服务器或中间代理仅支持 HTTP/1.0,或者没有正确遵循 HTTP 标准时,才应该提高这个限制。</span><br><span class=line>一般来说,增大这个值并不能解决大多数 Git 推送问题。同时它还可能显著增加内存占用,因为即使实际推送的数据很小,Git 也会分配完整大小的缓冲区。</span><br></pre></table></figure><p>对于我这样的hexo是在.deploy_git目录里的.git/config文件<br>普通git仓库如果要配置就是在.git/config里进行配置<figure class="highlight shell"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br><span class=line>3</span><br></pre><td class=code><pre><span class=line>[http]</span><br><span class=line> postBuffer = 16777216</span><br><span class=line> version = HTTP/1.1</span><br></pre></table></figure><p>可以直接改这个文件,也可以用git配置命令<figure class="highlight shell"><table><tr><td class=gutter><pre><span class=line>1</span><br><span class=line>2</span><br></pre><td class=code><pre><span class=line>git config http.postBuffer 16777216</span><br><span class=line>git config http.version HTTP/1.1</span><br></pre></table></figure><p>这样都可以,在现在这个时代<br>发现这样一个小技巧或者小问题的答案<br>我还是想记录下<br>因为很多的东西感觉已经被GPT这样的颠覆掉了<br>有这些小的问题被解决<br>感觉有种久违的愉悦感<br>排查问题,找到原因是个很有意思的过程<br>并把它解决也是很有意思<br>这个可能就算是初心了吧<br>就能把解决问题的思路方法分享下<br>也是一种比较开始的事情</div><footer class=post-footer><div class=post-eof></div></footer></article></div><nav class=pagination><span class="page-number current">1</span><a class=page-number href=/page/2/>2</a><span class=space>…</span><a class=page-number href=/page/77/>77</a><a class="extend next" aria-label=下一页 href=/page/2/ rel=next title=下一页><i class="fa fa-angle-right"></i></a></nav></div></main><footer class=footer><div class=footer-inner><div class=beian><a href=https://beian.miit.gov.cn/ rel=noopener target=_blank>浙ICP备16002580号-2 </a><img alt src=/uploads/beian.png><a href=https://beian.mps.gov.cn/#/query/webSearch?code=33010602011094 rel=noopener target=_blank>浙公网安备 33010602011094号</a></div><div class=copyright>© <span itemprop=copyrightYear>2026</span><span class=with-love><i class="fa fa-heart"></i> </span><span class=author itemprop=copyrightHolder>Nicksxs</span></div><div class=busuanzi-count><span class=post-meta-item id=busuanzi_container_site_uv><span class=post-meta-item-icon><i class="fa fa-user"></i> </span><span class=site-uv title=总访客量><span id=busuanzi_value_site_uv></span> </span></span><span class=post-meta-item id=busuanzi_container_site_pv><span class=post-meta-item-icon><i class="fa fa-eye"></i> </span><span class=site-pv title=总访问量><span id=busuanzi_value_site_pv></span></span></span></div></div></footer><div aria-label=返回顶部 class=back-to-top role=button><i class="fa fa-arrow-up fa-lg"></i><span>0%</span></div><a aria-label="在 GitHub 上关注我" title="在 GitHub 上关注我" class=github-corner href=https://github.com/nicksxs rel=noopener target=_blank><svg viewbox="0 0 250 250" aria-hidden=true height=80 width=80><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" style="transform-origin:130px 106px" class=octo-arm fill=currentColor></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" class=octo-body fill=currentColor></path></svg></a><noscript><div class=noscript-warning>Theme NexT works best with JavaScript enabled</div></noscript><script crossorigin=anonymous integrity=sha256-XL2inqUJaslATFnHdJOi9GfQ60on8Wx1C2H8DYiN1xY= src=https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js></script><script crossorigin=anonymous integrity=sha256-ytMJGN3toR+a84u7g7NuHm91VIR06Q41kMWDr2pq7Zo= src=https://cdnjs.cloudflare.com/ajax/libs/fancyapps-ui/5.0.28/fancybox/fancybox.umd.js></script><script crossorigin=anonymous integrity=sha256-mOFREFhqmHeQbXpK2lp4nA3qooVgACfh88fpJftLBbc= src=https://cdnjs.cloudflare.com/ajax/libs/lozad.js/1.16.0/lozad.min.js></script><script src=/js/comments.js></script><script src=/js/utils.js></script><script src=/js/motion.js></script><script src=/js/next-boot.js></script><script crossorigin=anonymous integrity=sha256-DABVk+hYj0mdUzo+7ViJC6cwLahQIejFvC+my2M/wfM= src=https://cdnjs.cloudflare.com/ajax/libs/algoliasearch/4.20.0/algoliasearch-lite.umd.js></script><script crossorigin=anonymous integrity=sha256-9242vN47QUX50UG5Gf5XDO1YREWCEJRyXHofh5fsl24= src=https://cdnjs.cloudflare.com/ajax/libs/instantsearch.js/4.60.0/instantsearch.production.min.js></script><script src=/js/third-party/search/algolia-search.js></script><script src=/js/third-party/fancybox.js></script><script async src=https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js></script><script crossorigin=anonymous integrity=sha256-yvJQOINiH9fWemHn0vCA5lsHWJaHs6/ZmO+1Ft04SvM= src=https://cdnjs.cloudflare.com/ajax/libs/quicklink/2.3.0/quicklink.umd.js></script><script class=next-config data-name=quicklink type=application/json>{"enable":false,"home":false,"archive":false,"delay":true,"timeout":3000,"priority":true,"url":"https://nicksxs.me/"}</script><script src=/js/third-party/quicklink.js></script><script data-cloudflare-page-counter-config type=application/json>{"enable":true,"endpoint":"https://counter.nicksxs.me","site":"nicksxs","local_cache":true,"timeout":5000,"icon":"far fa-eye","item_text":true}</script><script src=/js/cloudflare-page-counter.js></script><script class=next-config data-name=disqus type=application/json>{"enable":true,"shortname":"nicksxs","count":true,"i18n":{"disqus":"disqus"}}</script><script src=/js/third-party/comments/disqus.js></script>